Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修改机床参数bug

This commit is contained in:
qihao.gong@jikimo.com
2024-04-23 10:11:38 +08:00
76 changed files with 4113 additions and 2292 deletions

View File

@@ -4,6 +4,7 @@ import {patch} from '@web/core/utils/patch';
// import { Dialog } from "@web/core/dialog/dialog"; // import { Dialog } from "@web/core/dialog/dialog";
import {_t} from "@web/core/l10n/translation"; import {_t} from "@web/core/l10n/translation";
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator"; import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
import {ListRenderer} from "@web/views/list/list_renderer";
import {Field} from "@web/views/fields/field"; import {Field} from "@web/views/fields/field";
@@ -42,7 +43,14 @@ const filedRequiredList = {
// 制造大模块 // 制造大模块
'production_line_id': { multiple: false, noLabel: false }, 'production_line_id': { multiple: false, noLabel: false },
'date_approve': { 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', { patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
// 你可以重写或者添加一些方法和属性 // 你可以重写或者添加一些方法和属性
async _onDiscardChanges() { async _onDiscardChanges() {
@@ -83,12 +91,8 @@ patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
); );
patch(Field.prototype, 'jikimo_frontend.Field', { patch(Field.prototype, 'jikimo_frontend.Field', {
setup() { 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); owl.onMounted(this.setRequired);
return this._super(...arguments);
}, },
setRequired() { setRequired() {
const id = this.props.id 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 () { $(function () {
document.addEventListener('click', function () { document.addEventListener('click', function () {
@@ -162,45 +198,13 @@ $(function () {
}, 500) }, 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 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 listenerUrl = setInterval(() => {
const isChange = currentUrl != location.href const isChange = currentUrl != location.href
if (isChange) { if (isChange) {
currentUrl = location.href currentUrl = location.href
customRequired() customRequired()
setRequired(customRequiredDom)
} }
}, 500) }, 500)
customRequired() customRequired()
setRequired(customRequiredDom)
}) })

View File

@@ -3,6 +3,13 @@
import { registry } from "@web/core/registry"; import { registry } from "@web/core/registry";
import { url } from "@web/core/utils/urls"; import { url } from "@web/core/utils/urls";
import { ImageField, imageCacheKey } from '@web/views/fields/image/image_field'; 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"; const placeholder = "/web/static/img/placeholder.png";
@@ -15,7 +22,7 @@ export class CustomImageField extends ImageField {
getUrl(previewFieldName) { getUrl(previewFieldName) {
console.log('8888888888886666666666666666666') console.log('8888888888886666666666666666666')
if (this.state.isValid && this.props.value) { if (this.state.isValid && this.props.value) {
if (1) { if (isBinarySize(this.props.value) || this.props.value.length < 50) {
if (!this.rawCacheKey) { if (!this.rawCacheKey) {
this.rawCacheKey = this.props.record.data.__last_update; this.rawCacheKey = this.props.record.data.__last_update;
} }

View File

@@ -467,3 +467,28 @@ div:has(.o_required_modifier) > label::before {
background: #71639e; background: #71639e;
color: #fff 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;
}

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from datetime import date from datetime import date
from odoo import fields, models, api from odoo import fields, models, api
from odoo.exceptions import UserError
class CuttingToolMaterial(models.Model): class CuttingToolMaterial(models.Model):
@@ -308,3 +309,41 @@ class ToolGroups(models.Model):
# records = super(ToolGroups, self).create(vals_list) # records = super(ToolGroups, self).create(vals_list)
# self._register_tool_groups(records) # self._register_tool_groups(records)
# return 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

View File

@@ -65,7 +65,7 @@
<record id="group_plan_dispatch" model="res.groups"> <record id="group_plan_dispatch" model="res.groups">
<field name="name">计划调度岗</field> <field name="name">计划调度岗</field>
<field name="category_id" ref="module_category_plan"/> <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>
<record id="group_plan_director" model="res.groups"> <record id="group_plan_director" model="res.groups">

View File

@@ -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_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,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_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,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_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,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_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,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_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,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_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,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_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_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 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_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_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,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_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_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 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_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_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_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_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_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 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,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_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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
9 access_sf_machine_brand_tags_admin sf_machine_brand_tags_admin model_sf_machine_brand_tags base.group_system 1 1 1 0
10 access_sf_machine_control_system sf_machine_control_system model_sf_machine_control_system base.group_user 1 1 1 0
11 access_sf_machine_control_system_admin sf_machine_control_system_admin model_sf_machine_control_system base.group_system 1 1 1 0
12 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
13 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
14 access_sf_production_process sf_production_process model_sf_production_process base.group_user 1 1 1 0
15 access_sf_production_process_admin sf_production_process_admin model_sf_production_process base.group_system 1 1 1 0
16 access_sf_production_materials sf_production_materials model_sf_production_materials base.group_user 1 1 1 0
17 access_sf_production_materials_admin access_sf_production_materials_group_sale_director sf_production_materials_admin sf_production_materials_group_sale_director model_sf_production_materials base.group_system sf_base.group_sale_director 1 1 0 1 0 0
18 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
19 access_sf_production_materials_admin sf_production_materials_admin model_sf_production_materials base.group_system 1 1 1 0
20 access_sf_materials_model sf_materials_model model_sf_materials_model base.group_user 1 1 1 0
21 access_sf_materials_model access_sf_materials_model_admin sf_materials_model sf_materials_model_admin model_sf_materials_model base.group_user base.group_system 1 1 1 0
22 access_sf_materials_model_admin access_sf_supplier_sort sf_materials_model_admin sf_supplier_sort model_sf_materials_model model_sf_supplier_sort base.group_system base.group_user 1 1 1 0
23 access_sf_supplier_sort access_sf_supplier_sort_admin sf_supplier_sort sf_supplier_sort_admin model_sf_supplier_sort base.group_user base.group_system 1 1 1 0
24 access_sf_supplier_sort_admin access_sf_production_process_parameter sf_supplier_sort_admin sf_production_process_parameter model_sf_supplier_sort model_sf_production_process_parameter base.group_system base.group_user 1 1 1 0
25 access_sf_production_process_parameter access_sf_production_process_parameter_group_sale_director sf_production_process_parameter sf_production_process_parameter_group_sale_director model_sf_production_process_parameter base.group_user sf_base.group_sale_director 1 1 0 1 0 0
26 access_sf_production_process_parameter_group_plan_director access_sf_production_process_parameter_group_sale_salemanager sf_production_process_parameter_group_plan_director sf_production_process_parameter_group_sale_salemanager model_sf_production_process_parameter sf_base.group_plan_director sf_base.group_sale_salemanager 1 0 0 0
27 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
28 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
29 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
30 access_sf_production_process_parameter_admin sf_production_process_parameter_admin model_sf_production_process_parameter base.group_system 1 1 1 0
31 access_sf_production_process_parameter_group_purchase_director access_sf_production_process_category sf_production_process_parameter_group_purchase_director sf_production_process_category model_sf_production_process_parameter model_sf_production_process_category sf_base.group_purchase_director base.group_user 1 0 1 0 1 0
32 access_sf_production_process_parameter_group_sale_director access_sf_production_process_category_admin sf_production_process_parameter_group_sale_director sf_production_process_category_admin model_sf_production_process_parameter model_sf_production_process_category sf_base.group_sale_director base.group_system 1 0 1 0 1 0
33 access_sf_production_process_parameter_admin access_sf_machine_tool_category sf_production_process_parameter_admin sf_machine_tool_category model_sf_production_process_parameter model_sf_machine_tool_category base.group_system base.group_user 1 1 1 0
110 access_sf_materials_model access_sf_materials_model_group_plan_director sf_materials_model sf_materials_model_group_plan_director model_sf_materials_model sf_base.group_sf_mrp_user sf_base.group_plan_director 1 0 0 0
111 access_sf_materials_model_group_plan_director access_sf_materials_model_group_purchase_director sf_materials_model_group_plan_director sf_materials_model_group_purchase_director model_sf_materials_model sf_base.group_plan_director sf_base.group_purchase_director 1 0 0 0
112 access_sf_materials_model_group_purchase_director access_sf_materials_model_group_sale_director sf_materials_model_group_purchase_director sf_materials_model_group_sale_director model_sf_materials_model sf_base.group_purchase_director sf_base.group_sale_director 1 0 0 0
113 access_sf_supplier_sort sf_supplier_sort model_sf_supplier_sort sf_base.group_sf_mrp_user 1 0 0 0
114 access_sf_production_process_parameter sf_production_process_parameter model_sf_production_process_parameter sf_base.group_sf_mrp_user 1 0 0 0
115 access_sf_production_process_category sf_production_process_category model_sf_production_process_category sf_base.group_sf_mrp_user 1 0 0 0
116 access_sf_machine_tool_category sf_machine_tool_category model_sf_machine_tool_category sf_base.group_sf_mrp_user 1 0 0 0
117 access_sf_materials_model_group_sale_director access_sf_cutting_tool_material_group_purchase_director sf_materials_model_group_sale_director sf_cutting_tool_material_group_purchase_director model_sf_materials_model model_sf_cutting_tool_material sf_base.group_sale_director sf_base.group_purchase_director 1 0 0 1 0
118 access_sf_supplier_sort access_sf_cutting_tool_material_group_sale_director sf_supplier_sort sf_cutting_tool_material_group_sale_director model_sf_supplier_sort model_sf_cutting_tool_material sf_base.group_sf_mrp_user sf_base.group_sale_director 1 0 0 1 0
119 access_sf_production_process_parameter access_sf_cutting_tool_material_group_plan_director sf_production_process_parameter sf_cutting_tool_material_group_plan_director model_sf_production_process_parameter model_sf_cutting_tool_material sf_base.group_sf_mrp_user sf_base.group_plan_director 1 0 0 1 0
158 access_sf_tool_groups_group_plan_dispatch access_purchase_order_line sf_tool_groups purchase.order.line model_sf_tool_groups purchase.model_purchase_order_line sf_base.group_plan_dispatch 1 0 0 0
159 access_sf_tool_groups_group_sf_tool_user access_account_move_line sf_tool_groups account.move.line model_sf_tool_groups account.model_account_move_line sf_base.group_sf_tool_user sf_base.group_plan_dispatch 1 1 0 1 0 1 0
160 access_purchase_order access_sf_machine_tool_type_group_plan_dispatch purchase.order sf.machine_tool.type purchase.model_purchase_order model_sf_machine_tool_type sf_base.group_plan_dispatch 1 0 0 0
161 access_sf_machine_tool sf_machine_tool model_sf_machine_tool sf_base.group_sf_mrp_user 1 1 0 0
162 access_res_partner access_sf_machine_tool_type res.partner sf_machine_tool_type base.model_res_partner model_sf_machine_tool_type sf_base.group_plan_dispatch sf_base.group_sf_mrp_user 1 0 1 0 0
163 access_purchase_order_line access_sf_machine_brand purchase.order.line sf_machine_brand purchase.model_purchase_order_line model_sf_machine_brand sf_base.group_plan_dispatch sf_base.group_sf_mrp_user 1 0 1 0 0
164 access_account_move_line access_sf_machine_brand_tags account.move.line sf_machine_brand_tags account.model_account_move_line model_sf_machine_brand_tags sf_base.group_plan_dispatch sf_base.group_sf_mrp_user 1 0 1 0 0
206 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
207 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
208 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
209 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
210 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
211 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
212 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
213 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
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229

View File

@@ -189,3 +189,6 @@ td.o_required_modifier {
flex-direction: row !important; flex-direction: row !important;
} }
.supplier_ids_set_css thead th[data-name=partner_id]{
width: 500px!important;
}

View File

@@ -231,6 +231,9 @@
<field name="name" string="名称搜索" filter_domain="[('name','ilike',self)]"/> <field name="name" string="名称搜索" filter_domain="[('name','ilike',self)]"/>
<field name="code" string="编码搜索" filter_domain="[('code','ilike',self)]"/> <field name="code" string="编码搜索" filter_domain="[('code','ilike',self)]"/>
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/> <filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
<searchpanel>
<field name="category_id" icon="fa-building" enable_counters="1"/>
</searchpanel>
</search> </search>
</field> </field>
</record> </record>
@@ -266,7 +269,7 @@
</group> </group>
<notebook> <notebook>
<page string="供应商"> <page string="供应商">
<field name='supplier_ids'> <field name='supplier_ids' class="supplier_ids_set_css">
<tree editable='bottom'> <tree editable='bottom'>
<field name="sequence" widget="handle" string="序号"/> <field name="sequence" widget="handle" string="序号"/>
<field name="partner_id" string="名称"/> <field name="partner_id" string="名称"/>

View File

@@ -59,16 +59,24 @@
id="menu_sf_cutting_tool_type" id="menu_sf_cutting_tool_type"
parent="menu_sf_cutting_tool" parent="menu_sf_cutting_tool"
name="刀具类型" name="刀具类型"
sequence="2" sequence="10"
action="action_sf_cutting_tool_type" action="action_sf_cutting_tool_type"
/> />
<menuitem <menuitem
id="menu_sf_cutting_tool_standard_library" id="menu_sf_cutting_tool_standard_library"
parent="menu_sf_cutting_tool" parent="menu_sf_cutting_tool"
name="刀具标准库" name="刀具标准库"
sequence="3" sequence="20"
action="action_sf_cutting_tool_standard_library" 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--> <!-- <menuitem-->
<!-- id="menu_sf_functional_cutting_tool"--> <!-- id="menu_sf_functional_cutting_tool"-->
@@ -82,7 +90,7 @@
id="menu_sf_functional_cutting_tool_model_type" id="menu_sf_functional_cutting_tool_model_type"
parent="menu_sf_cutting_tool" parent="menu_sf_cutting_tool"
name="功能刀具类型" name="功能刀具类型"
sequence="4" sequence="30"
action="action_sf_functional_cutting_tool_model_type" action="action_sf_functional_cutting_tool_model_type"
/> />
@@ -91,14 +99,14 @@
name="能力特征库" name="能力特征库"
parent="menu_sf_cutting_tool" parent="menu_sf_cutting_tool"
action="action_maintenance_equipment_image" action="action_maintenance_equipment_image"
sequence="5"/> sequence="40"/>
<menuitem <menuitem
id="menu_sf_tool_groups" id="menu_sf_tool_groups"
name="刀具组" name="刀具组"
parent="menu_sf_cutting_tool" parent="menu_sf_cutting_tool"
action="sf_tool_groups_view_act" action="sf_tool_groups_view_act"
sequence="10"/> sequence="50"/>
</data> </data>
</odoo> </odoo>

View File

@@ -547,7 +547,66 @@
<!-- <field name="cutting_depth"/>--> <!-- <field name="cutting_depth"/>-->
<!-- </tree>--> <!-- </tree>-->
<!-- </field>--> <!-- </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> </odoo>

View File

@@ -10,6 +10,7 @@
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/> <field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name='is_bfm' invisible="1"/> <field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/> <field name='categ_type' invisible="1"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file" <field name="upload_model_file"
widget="many2many_binary" widget="many2many_binary"
attrs="{'invisible': ['|', '|',('categ_type', '!=', '成品'),('categ_type', '=', False),('is_bfm','=', True)]}"/> 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}" 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)]}" attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"
domain="[('standard_library_id','=',cutting_tool_model_id)]"/> 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}"/> placeholder="请选择" options="{'no_create': True}"/>
<field name="fixture_model_id" string="型号" placeholder="请选择" options="{'no_create': True}" <field name="fixture_model_id" string="型号" placeholder="请选择" options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}" attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
domain="[('fixture_material_id','=',fixture_material_id)]"/> domain="[('fixture_material_id','=',fixture_material_id)]"/>
<field name="specification_fixture_id" string="规格" placeholder="请选择" <field name="specification_fixture_id" string="规格" placeholder="请选择"
options="{'no_create': True}" options="{'no_create': True}"
attrs="{'invisible': [('categ_type', '!=', '夹具')]}" attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
domain="[('fixture_model_id','=',fixture_model_id)]"/> domain="[('fixture_model_id','=',fixture_model_id)]"/>
</field> </field>
<xpath expr="//label[@for='volume']" position="before"> <xpath expr="//label[@for='volume']" position="before">

View File

@@ -148,7 +148,7 @@ class SfMaintenanceEquipment(models.Model):
MTcode = fields.Char("机台编码") MTcode = fields.Char("机台编码")
created_user = fields.Many2one('res.users', string='创建人', default=lambda self: self.env.user) created_user = fields.Many2one('res.users', string='创建人', default=lambda self: self.env.user)
equipment_type = fields.Selection([('机床', '机床'), ('机器人', '机器人'), ('AGV小车', 'AGV小车'), equipment_type = fields.Selection([('机床', '机床'), ('机器人', '机器人'), ('AGV小车', 'AGV小车'),
('检测设备', '检测设备')], compute='_compute_category_id') ('检测设备', '检测设备'), ('其他', '其他')], compute='_compute_category_id')
@api.depends('category_id') @api.depends('category_id')
def _compute_category_id(self): def _compute_category_id(self):

View File

@@ -24,6 +24,7 @@
'views/mrp_workcenter_views.xml', 'views/mrp_workcenter_views.xml',
'views/mrp_workorder_view.xml', 'views/mrp_workorder_view.xml',
'views/model_type_view.xml', 'views/model_type_view.xml',
'views/agv_setting_views.xml',
'views/sf_maintenance_equipment.xml', 'views/sf_maintenance_equipment.xml',
], ],

View File

@@ -1,6 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
import json import json
from datetime import datetime
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
@@ -114,7 +115,7 @@ class Manufacturing_Connect(http.Controller):
logging.info('RfidCode:%s' % ret['RfidCode']) logging.info('RfidCode:%s' % ret['RfidCode'])
if 'RfidCode' in ret: if 'RfidCode' in ret:
workorder = request.env['mrp.workorder'].sudo().search( 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: if workorder:
for item in workorder: for item in workorder:
if item.material_center_point: if item.material_center_point:
@@ -122,8 +123,8 @@ class Manufacturing_Connect(http.Controller):
res['Datas'].append({ res['Datas'].append({
'XOffset': 0 if not item.material_center_point else offset[0], 'XOffset': 0 if not item.material_center_point else offset[0],
'YOffset': 0 if not item.material_center_point else offset[1], 'YOffset': 0 if not item.material_center_point else offset[1],
'ZOffet': 0 if not item.material_center_point else offset[2], 'ZOffset': 0 if not item.material_center_point else offset[2],
'COffset': 0 if not item.X_deviation_angle else item.X_deviation_angle, 'COffset': 0,
'Coordinate': 'G54' 'Coordinate': 'G54'
}) })
else: else:
@@ -238,7 +239,7 @@ class Manufacturing_Connect(http.Controller):
workorder = request.env['mrp.workorder'].sudo().search( workorder = request.env['mrp.workorder'].sudo().search(
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1) [('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
if workorder: if workorder:
workorder.test_result = ret['Quality'] # workorder.test_results = ret['Quality']
logging.info('制造订单:%s' % workorder.production_id.name) logging.info('制造订单:%s' % workorder.production_id.name)
if 'ReportPaht' in ret: if 'ReportPaht' in ret:
download_state = request.env['mrp.workorder'].with_user( download_state = request.env['mrp.workorder'].with_user(
@@ -261,8 +262,7 @@ class Manufacturing_Connect(http.Controller):
('picking_id', '=', stock_picking.id)]) ('picking_id', '=', stock_picking.id)])
if quality_check: if quality_check:
logging.info('质检单:%s' % quality_check.name) logging.info('质检单:%s' % quality_check.name)
quality_check.write({'report_pdf': workorder.detection_report, quality_check.write({'report_pdf': workorder.detection_report})
'report_result': workorder.test_result})
elif download_state == 2: elif download_state == 2:
res = {'Succeed': False, 'ErrorCode': 205, res = {'Succeed': False, 'ErrorCode': 205,
'Error': 'ReportPaht中的工件号与制造订单%s不匹配请检查ReportPaht是否正确' % workorder.production_id.name} 'Error': 'ReportPaht中的工件号与制造订单%s不匹配请检查ReportPaht是否正确' % workorder.production_id.name}
@@ -431,14 +431,15 @@ class Manufacturing_Connect(http.Controller):
if 'DeviceId' in ret: if 'DeviceId' in ret:
logging.info('DeviceId:%s' % ret['DeviceId']) logging.info('DeviceId:%s' % ret['DeviceId'])
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( 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: if workpiece_delivery:
for wd in workpiece_delivery: for wd in workpiece_delivery:
logging.info('wd.workorder_id:%s' % wd.workorder_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_id:%s' % wd.production_id.name)
if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '待上产线':
logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state) logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state)
wd.production_id.write({'production_line_state': '已上产线'}) wd.production_id.write({'production_line_state': '已上产线'})
wd.write({'production_line_state': '已上产线'})
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'}
else: else:
@@ -465,14 +466,28 @@ class Manufacturing_Connect(http.Controller):
if 'DeviceId' in ret: if 'DeviceId' in ret:
logging.info('DeviceId:%s' % ret['DeviceId']) logging.info('DeviceId:%s' % ret['DeviceId'])
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( 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: if workpiece_delivery:
for wd in workpiece_delivery: for wd in workpiece_delivery:
logging.info('wd.workorder_id:%s' % wd.workorder_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_id:%s' % wd.production_id.name)
if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '已上产线':
logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state) 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': '已下产线'}) wd.production_id.write({'production_line_state': '已下产线'})
logging.info('开始向agv下发下产线任务')
workpiece_delivery_off._delivery_avg()
logging.info('agv下发下产线任务已配送')
else: else:
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'} res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'}
else: else:
@@ -481,3 +496,35 @@ class Manufacturing_Connect(http.Controller):
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('AGVDownProduct error:%s' % e) logging.info('AGVDownProduct error:%s' % e)
return json.JSONEncoder().encode(res) 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)

View File

@@ -25,7 +25,7 @@ class Workpiece(http.Controller):
if 'method' in ret: if 'method' in ret:
if ret['method'] == 'end': if ret['method'] == 'end':
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search( 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: if workpiece_delivery:
workpiece_delivery.write({'status': '已配送', 'task_completion_time': ret['reqTime']}) workpiece_delivery.write({'status': '已配送', 'task_completion_time': ret['reqTime']})
else: else:

View File

@@ -67,5 +67,21 @@
search="[('barcode','=','WH-PREPRODUCTION')]"/> search="[('barcode','=','WH-PREPRODUCTION')]"/>
<field name="default_location_dest_id" ref="stock_location_locations_virtual_outcontract"/> <field name="default_location_dest_id" ref="stock_location_locations_virtual_outcontract"/>
</record> </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> </data>
</odoo> </odoo>

View File

@@ -8,3 +8,4 @@ from . import mrp_routing_workcenter
from . import stock from . import stock
from . import res_user from . import res_user
from . import production_line_base from . import production_line_base
from . import agv_setting

View 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)

View File

@@ -54,9 +54,12 @@ class MrpProduction(models.Model):
glb_file = fields.Binary("glb模型文件") glb_file = fields.Binary("glb模型文件")
production_line_id = fields.Many2one('sf.production.line', string='生产线') production_line_id = fields.Many2one('sf.production.line', string='生产线')
plan_start_processing_time = fields.Datetime('计划开始加工时间') plan_start_processing_time = fields.Datetime('计划开始加工时间')
production_line_state = fields.Selection([('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')], production_line_state = fields.Selection(
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
string='上/下产线', default='待上产线') string='上/下产线', default='待上产线')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
@api.depends( @api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state') 'workorder_ids.state', 'product_qty', 'qty_producing', 'schedule_state')
@@ -132,6 +135,15 @@ class MrpProduction(models.Model):
# cnc程序获取 # cnc程序获取
def fetchCNC(self): def fetchCNC(self):
cnc = self.env['mrp.production'].search([('id', '=', self.id)]) 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: try:
res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code, res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
'production_no': cnc.name, '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_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, 'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
'order_no': cnc.origin, 'order_no': cnc.origin,
'model_order_no': cnc.product_id.default_code.rsplit(' -', 1)[0], 'model_order_no': cnc.product_id.default_code,
'user': cnc.env.user.name, 'user': cnc.env.user.name,
'programme_way': programme_way,
'model_file': '' if not cnc.product_id.model_file else base64.b64encode( 'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
cnc.product_id.model_file).decode('utf-8') cnc.product_id.model_file).decode('utf-8')
} }

View File

@@ -1,10 +1,14 @@
import re
import logging import logging
import base64 import base64
import urllib.parse
from datetime import date from datetime import date
from datetime import datetime, timedelta from datetime import datetime, timedelta
import requests import requests
import os import os
import math import math
from lxml import etree
from dateutil.relativedelta import relativedelta from dateutil.relativedelta import relativedelta
# import subprocess # import subprocess
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models, SUPERUSER_ID, _
@@ -42,6 +46,8 @@ class ResMrpWorkOrder(models.Model):
], string="工序类型") ], string="工序类型")
results = fields.Char('结果') results = fields.Char('结果')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
@api.onchange('users_ids') @api.onchange('users_ids')
def get_user_permissions(self): def get_user_permissions(self):
uid = self.env.uid uid = self.env.uid
@@ -95,11 +101,12 @@ class ResMrpWorkOrder(models.Model):
Y10_axis = fields.Float(default=0) Y10_axis = fields.Float(default=0)
Z10_axis = fields.Float(default=0) Z10_axis = fields.Float(default=0)
X_deviation_angle = fields.Integer(string="X轴偏差度", 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加工程序") cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序") cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
tray_code = fields.Char(string="托盘编码") 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='是否外协') is_subcontract = fields.Boolean(string='是否外协')
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
picking_in_id = fields.Many2one('stock.picking', 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='加工人') processing_user_id = fields.Many2one('res.users', string='加工人')
# 检测人 # 检测人
inspection_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) schedule_state = fields.Selection(related='production_id.schedule_state', store=True)
# 工件装夹信息 # 工件装夹信息
functional_fixture_code = fields.Char(string="功能夹具编码", readonly=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', production_line_state = fields.Selection(related='production_id.production_line_state',
string='上/下产线', store=True) string='上/下产线', store=True)
detection_report = fields.Binary('检测报告', readonly=True) detection_report = fields.Binary('检测报告', readonly=True)
is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True)
def get_plan_workorder(self, production_line): def get_plan_workorder(self, production_line):
tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d") 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)]) [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_id)])
return process_parameter_workorder 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轴倾斜度方法 # 计算配料中心点和与x轴倾斜度方法
def getcenter(self): def getcenter(self):
try: try:
@@ -202,6 +366,7 @@ class ResMrpWorkOrder(models.Model):
y7 = self.Y7_axis y7 = self.Y7_axis
y8 = self.Y8_axis y8 = self.Y8_axis
z1 = self.Z9_axis z1 = self.Z9_axis
z2 = self.Z10_axis
x0 = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / ( x0 = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / (
(x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4)) (x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4))
y0 = ((y3 - y4) * (y2 * x1 - y1 * x2) - (y1 - y2) * (y4 * x3 - y3 * x4)) / ( 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)) (y7 - y8) * (x5 - x6) - (y5 - y6) * (x7 - x8))
x = (x0 + x1) / 2 x = (x0 + x1) / 2
y = (y0 + y1) / 2 y = (y0 + y1) / 2
z = z1 / 2 z = (z1 + z2) / 2
jd = math.atan2((x5 - x6), (y5 - y6)) jd = math.atan2((x5 - x6), (y5 - y6))
jdz = jd * 180 / math.pi jdz = jd * 180 / math.pi
@@ -225,17 +390,19 @@ class ResMrpWorkOrder(models.Model):
work.compensation_value_x = eval(self.material_center_point)[0] work.compensation_value_x = eval(self.material_center_point)[0]
work.compensation_value_y = eval(self.material_center_point)[1] work.compensation_value_y = eval(self.material_center_point)[1]
workorder.button_finish() workorder.button_finish()
except: except Exception as e:
raise UserError("参数计算有误") # 重新抛出捕获到的异常信息
raise UserError(str(e))
def button_workpiece_delivery(self): def button_workpiece_delivery(self):
if self.routing_type == '装夹预调': if self.routing_type == '装夹预调':
for item in self.workpiece_delivery_ids: for item in self.workpiece_delivery_ids:
if not item.feeder_station_start: if not item.route_id:
raise UserError('【工件配送】明细中请输入起点接驳站') raise UserError('【工件配送】明细中请选择【任务路线】')
# if not item.workpiece_code: # if not item.workpiece_code:
# raise UserError('请对【同运工件】进行扫描') # raise UserError('请对【同运工件】进行扫描')
else: else:
if self.cnc_program_down_state == '已下发':
if item.status == '待下发': if item.status == '待下发':
return { return {
'name': _('确认'), 'name': _('确认'),
@@ -246,6 +413,8 @@ class ResMrpWorkOrder(models.Model):
'context': { 'context': {
'default_workorder_id': self.id, 'default_workorder_id': self.id,
}} }}
else:
raise UserError(_("该制造订单还未下发CNC程序单无法进行工件配送"))
# 拼接工单对象属性值 # 拼接工单对象属性值
def json_workorder_str(self, k, production, route): 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) values = self.env['mrp.production'].create_production1_values(self.production_id)
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
self.production_id.company_id).create( self.production_id.company_id).create(
@@ -475,7 +644,7 @@ class ResMrpWorkOrder(models.Model):
'mail.message_origin_link', 'mail.message_origin_link',
values={'self': production, 'origin': origin_production}, values={'self': production, 'origin': origin_production},
subtype_id=self.env.ref('mail.mt_note').id) subtype_id=self.env.ref('mail.mt_note').id)
if self.test_result == '返工': if self.test_results == '返工':
productions = self.production_id productions = self.production_id
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
@@ -483,47 +652,6 @@ class ResMrpWorkOrder(models.Model):
else: else:
self.results = '合格' 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): def json_workorder_str1(self, k, production, route):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
'product_uom_id': production.product_uom_id.id, 'product_uom_id': production.product_uom_id.id,
@@ -555,6 +683,12 @@ class ResMrpWorkOrder(models.Model):
picking_out.write({'state': 'assigned'}) picking_out.write({'state': 'assigned'})
if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress': 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 = 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() 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)): 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 return True
@@ -605,6 +739,8 @@ class ResMrpWorkOrder(models.Model):
if self.routing_type == '装夹预调': if self.routing_type == '装夹预调':
if not self.material_center_point and self.X_deviation_angle > 0: if not self.material_center_point and self.X_deviation_angle > 0:
raise UserError("请对前置三元检测定位参数进行计算定位") raise UserError("请对前置三元检测定位参数进行计算定位")
if not self.rfid_code:
raise UserError("请扫RFID码进行绑定")
if self.picking_out_id: if self.picking_out_id:
picking_out = self.env['stock.picking'].search([('id', '=', self.picking_out_id.id)]) picking_out = self.env['stock.picking'].search([('id', '=', self.picking_out_id.id)])
if picking_out.workorder_out_id: if picking_out.workorder_out_id:
@@ -647,7 +783,7 @@ class ResMrpWorkOrder(models.Model):
production_no_ftp = reportpath.split('/') production_no_ftp = reportpath.split('/')
production_no = workorder.production_id.name.replace('/', '_') production_no = workorder.production_id.name.replace('/', '_')
# ftp地址 # 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) logging.info('ftp地址:%s' % remotepath)
if reportpath.find(production_no) != -1: if reportpath.find(production_no) != -1:
# 服务器内临时地址 # 服务器内临时地址
@@ -726,7 +862,7 @@ class CNCprocessing(models.Model):
'cutting_tool_handle_type': obj['cutting_tool_handle_type'], 'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
'estimated_processing_time': obj['estimated_processing_time'], 'estimated_processing_time': obj['estimated_processing_time'],
'remark': obj['remark'], '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_processing.get_cnc_processing_file(program_path_tmp, cnc_processing, program_path)
# cnc_workorder.state = 'done' # cnc_workorder.state = 'done'
@@ -735,7 +871,7 @@ class CNCprocessing(models.Model):
# cnc_workorder.time_ids.date_end = datetime.now() # cnc_workorder.time_ids.date_end = datetime.now()
# cnc_workorder.button_finish() # cnc_workorder.button_finish()
# 根据程序名和加工面匹配到ftp里对应的Nc程序名 # 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path): def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
logging.info('serverdir:%s' % serverdir) logging.info('serverdir:%s' % serverdir)
for root, dirs, files in os.walk(serverdir): for root, dirs, files in os.walk(serverdir):
@@ -765,7 +901,7 @@ class CNCprocessing(models.Model):
# 将FTP的nc文件下载到临时目录 # 将FTP的nc文件下载到临时目录
def download_file_tmp(self, production_no, processing_panel): 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) serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
ftp_resconfig = self.env['res.config.settings'].get_values() 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 = 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里 # 将nc文件存到attach的datas里
def write_file(self, nc_file_path, cnc): def write_file(self, nc_file_path, cnc):
nc_file_name = nc_file_path.split('/') 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): if os.path.exists(nc_file_path):
with open(nc_file_path, 'rb') as file: with open(nc_file_path, 'rb') as file:
data_bytes = file.read() 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'].browse(self.ids)
# workorder = self.env['mrp.workorder'].search( # workorder = self.env['mrp.workorder'].search(
# [('routing_type', '=', '装夹预调'), ('production_id', '=', self.production_id.id)]) # [('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:
if workorder.routing_type == '装夹预调': if workorder.routing_type == '装夹预调':
stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)]) if workorder.state in ['done']:
if stock_move_line.product_id.categ_type == '夹具': work_state = {'done': '已完工'}
workorder.write({ raise UserError('装夹%s,请勿重复扫码' % work_state.get(workorder.state))
'tray_serial_number': stock_move_line.lot_name, lots = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
'tray_product_id': stock_move_line.product_id.id, logging.info("托盘信息:%s" % lots)
'tray_brand_id': stock_move_line.product_id.brand_id.id, if lots:
'tray_type_id': stock_move_line.product_id.fixture_material_id.id, for lot in lots:
'tray_model_id': stock_move_line.product_id.fixture_model_id.id if lot.product_id.categ_type == '夹具':
}) val = {
workorder.button_start() 'tray_serial_number': lot.name,
# return { 'tray_product_id': lot.product_id.id,
# 'type': 'ir.actions.act_window', 'tray_brand_id': lot.product_id.brand_id.id,
# 'res_model': 'mrp.workorder', 'tray_type_id': lot.product_id.fixture_material_id.id,
# 'view_mode': 'form', 'tray_model_id': lot.product_id.fixture_model_id.id,
# 'domain': [('id', 'in', workorder.id)], 'rfid_code': barcode
# 'target': 'current' }
# } 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: else:
embryo_stock_lot = self.env['stock.lot'].search([('name', '=', barcode)]) embryo_stock_lot = self.env['stock.lot'].search([('name', '=', barcode)])
if embryo_stock_lot: if embryo_stock_lot:
@@ -868,7 +1014,58 @@ class SfWorkOrderBarcodes(models.Model):
[('production_id', '=', workorder.production_id.id)]) [('production_id', '=', workorder.production_id.id)])
if workorder_rfid: if workorder_rfid:
for item in workorder_rfid: for item in workorder_rfid:
if item.state == "progress":
item.write({'rfid_code': barcode}) 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): class WorkPieceDelivery(models.Model):
@@ -882,17 +1079,32 @@ class WorkPieceDelivery(models.Model):
store=True) store=True)
plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True) plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
workpiece_code = fields.Char('同运工件编码') workpiece_code = fields.Char('同运工件编码')
feeder_station_start = fields.Char('起点接驳站') route_id = fields.Many2one('sf.agv.task.route', '任务路线')
feeder_station_destination = fields.Char('目的接驳站') feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站')
feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站')
task_delivery_time = fields.Datetime('任务下发时间') task_delivery_time = fields.Datetime('任务下发时间')
task_completion_time = fields.Datetime('任务完成时间') task_completion_time = fields.Datetime('任务完成时间')
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration') delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
status = fields.Selection( status = fields.Selection(
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态', [('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态',
default='待下发') 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): def button_delivery(self):
if self.cnc_program_down_state == '待下发':
if self.route_id:
if self.status == '待下发': if self.status == '待下发':
return { return {
'name': _('确认'), 'name': _('确认'),
@@ -905,30 +1117,50 @@ class WorkPieceDelivery(models.Model):
}} }}
else: else:
raise UserError('状态为【待下发】的工件记录可进行配送') raise UserError('状态为【待下发】的工件记录可进行配送')
else:
raise UserError('请选择任务路线再进行配送')
else:
raise UserError(_("该制造订单还未下发CNC程序单,无法进行工件配送"))
# 配送至avg小车 # 配送至avg小车
def _delivery_avg(self): 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': '', 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': '', 'podDir': '', 'materialLot': '', 'priority': '', 'taskCode': '', 'agvCode': '', 'materialLot': '',
'data': ''} 'data': ''}
config = self.env['res.config.settings'].get_values()
try: try:
logging.info('config-AGV请求路径:%s' % config['agv_rcms_url']) config['agv_rcs_url'] = 'http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask'
logging.info('config-json:%s' % res) logging.info('AGV请求路径:%s' % config['agv_rcs_url'])
ret = requests.post((config['agv_rcms_url']), json=res) 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() ret = ret.json()
logging.info('config-ret:%s' % ret) logging.info('config-ret:%s' % ret)
if ret['code'] == 0: if ret['code'] == 0:
if self.production_id.name == ret['reqCode']: 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: else:
raise UserError(ret['message']) raise UserError(ret['message'])
except Exception as e: except Exception as e:
logging.info('config-e:%s' % e) logging.info('config-e:%s' % e)
raise UserError("工件配送请求agv失败") raise UserError("工件配送请求agv失败")
@api.depends('production_id.production_line_id') @api.onchange('production_id.production_line_id')
def _compute_production_line_id(self): def _compute_production_line_id(self):
if self.production_id.production_line_id: if self.production_id.production_line_id:
self.production_line_id = self.production_id.production_line_id.id self.production_line_id = self.production_id.production_line_id.id
@@ -948,7 +1180,77 @@ class CMMprogram(models.Model):
_name = 'sf.cmm.program' _name = 'sf.cmm.program'
_description = "CMM程序" _description = "CMM程序"
program_path = fields.Char('程序文件路径') cmm_id = fields.Many2one('ir.attachment')
post_processing_name = fields.Char('后处理名称') sequence_number = fields.Integer('序号')
program_date = fields.Datetime('程序日期') 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="工单") 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

View File

@@ -1,15 +1,14 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
import requests
import base64 import base64
import hashlib import hashlib
import os import os
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.modules import get_resource_path 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): class ResProductMo(models.Model):
@@ -107,7 +106,10 @@ class ResProductMo(models.Model):
@api.onchange('cutting_tool_model_id') @api.onchange('cutting_tool_model_id')
def _onchange_cutting_tool_model_id(self): 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') @api.onchange('cutting_tool_material_id')
def _onchange_cutting_tool_material_id(self): 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_is_safety_lock = self.specification_id.is_safe_lock
self.cutting_tool_fit_nut_model = self.specification_id.nut self.cutting_tool_fit_nut_model = self.specification_id.nut
self.cutting_tool_wrench = self.specification_id.spanner 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_jump_accuracy = self.specification_id.diameter_slip_accuracy
self.cutting_tool_taper_shank_model = self.specification_id.taper_shank_model self.cutting_tool_taper_shank_model = self.specification_id.taper_shank_model
self.cutting_tool_cooling_type = self.specification_id.cooling_model self.cutting_tool_cooling_type = self.specification_id.cooling_model
@@ -521,6 +522,9 @@ class ResProductMo(models.Model):
string='注册状态', default='未注册') string='注册状态', default='未注册')
industry_code = fields.Char('行业编码', readonly=True) industry_code = fields.Char('行业编码', readonly=True)
# bfm下单
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
@api.constrains('tool_length') @api.constrains('tool_length')
def _check_tool_length_size(self): def _check_tool_length_size(self):
if self.tool_length > 1000000: if self.tool_length > 1000000:
@@ -615,6 +619,7 @@ class ResProductMo(models.Model):
'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']), 'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
'model_remark': item['remark'], 'model_remark': item['remark'],
'default_code': '%s-%s' % (order_number, i), 'default_code': '%s-%s' % (order_number, i),
'manual_quotation': item['manual_quotation'] or False,
'active': True, 'active': True,
} }
copy_product_id.sudo().write(vals) copy_product_id.sudo().write(vals)
@@ -888,6 +893,33 @@ class SfMaintenanceEquipmentAndProductTemplate(models.Model):
vals.append(res) vals.append(res)
return vals[0] 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): class SfMaintenanceEquipmentTool(models.Model):
_name = 'maintenance.equipment.tool' _name = 'maintenance.equipment.tool'

View File

@@ -17,6 +17,50 @@ from io import BytesIO
from odoo.exceptions import ValidationError 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): class StockRule(models.Model):
_inherit = 'stock.rule' _inherit = 'stock.rule'
@@ -222,6 +266,21 @@ class ProductionLot(models.Model):
_name = 'stock.lot' _name = 'stock.lot'
_inherit = ['stock.lot', 'printing.utils'] _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 @api.model
def generate_lot_names1(self, display_name, first_lot, count): def generate_lot_names1(self, display_name, first_lot, count):
"""Generate `lot_names` from a string.""" """Generate `lot_names` from a string."""
@@ -258,13 +317,15 @@ class ProductionLot(models.Model):
""" """
now = datetime.now().strftime("%Y%m%d") now = datetime.now().strftime("%Y%m%d")
last_serial = self.env['stock.lot'].search( 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') limit=1, order='id DESC')
if product.cutting_tool_model_id: if product.cutting_tool_model_id:
split_codes = product.cutting_tool_model_id.code.split('-')
if not last_serial: 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: 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: else:
raise ValidationError('该刀具物料产品的型号字段为空,请补充完整!!!') 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] return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name, 2)[1]
now = datetime.now().strftime("%Y%m%d") now = datetime.now().strftime("%Y%m%d")
if product.cutting_tool_model_id: 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) return "%s-%03d" % (product.name, 1)
qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code') qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
@@ -319,7 +381,7 @@ class ProductionLot(models.Model):
# port = 9100 # 可以根据实际情况修改 # 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: if not printer_config:
raise UserError('请先配置打印机') raise UserError('请先配置打印机')
host = printer_config.printer_id.ip_address host = printer_config.printer_id.ip_address
@@ -366,10 +428,10 @@ class StockPicking(models.Model):
# 设置外协出入单的名称 # 设置外协出入单的名称
def _get_name_Res(self, rescode): def _get_name_Res(self, rescode):
last_picking = self.sudo().search([('name', 'like', rescode)], order='create_date DESC', limit=1) last_picking = self.sudo().search([('name', 'like', rescode)], order='create_date DESC', limit=1)
logging.info('编号:' + last_picking.name)
if not last_picking: if not last_picking:
num = "%04d" % 1 num = "%04d" % 1
else: else:
logging.info('编号:' + last_picking.name)
m = int(last_picking.name[-3:]) + 1 m = int(last_picking.name[-3:]) + 1
num = "%04d" % m num = "%04d" % m
return '%s%s' % (rescode, num) return '%s%s' % (rescode, num)
@@ -419,7 +481,7 @@ class StockPicking(models.Model):
location_id = self.env.ref( location_id = self.env.ref(
'sf_manufacturing.stock_location_locations_virtual_outcontract').id, 'sf_manufacturing.stock_location_locations_virtual_outcontract').id,
location_dest_id = self.env['stock.location'].search( location_dest_id = self.env['stock.location'].search(
[('barcode', '=', 'WH-PREPRODUCTION')]).id, [('barcode', 'ilike', 'WH-PREPRODUCTION')]).id,
outcontract_picking_type_in = self.env.ref( outcontract_picking_type_in = self.env.ref(
'sf_manufacturing.outcontract_picking_in').id, 'sf_manufacturing.outcontract_picking_in').id,
outcontract_picking_type_out = self.env.ref( outcontract_picking_type_out = self.env.ref(
@@ -480,6 +542,65 @@ class ReStockMove(models.Model):
else: else:
raise UserError(_("没有可打印的标签数据")) 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): class ReStockQuant(models.Model):
_inherit = 'stock.quant' _inherit = 'stock.quant'

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

@@ -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_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_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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
130
131
132
133
134
135

View 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>

View File

@@ -422,7 +422,8 @@
<div name="product_specification_id" class="mt-1"> <div name="product_specification_id" class="mt-1">
规格: 规格:
<field name="specification_id"></field> <field name="specification_id"/>
<field name="specification_fixture_id"/>
</div> </div>
<t t-if="record.default_code.value">[<field name="default_code"/>] <t t-if="record.default_code.value">[<field name="default_code"/>]
</t> </t>

View File

@@ -46,6 +46,9 @@
<attribute name="invisible">1</attribute> <attribute name="invisible">1</attribute>
</xpath> </xpath>
<xpath expr="//field[@name='name']" position="after">
<field name="production_id"/>
</xpath>
<!-- <button name="button_start" type="object" string="Start" class="btn-success"--> <!-- <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)]}"/>--> <!-- 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"--> <!-- <button name="button_pending" type="object" string="Pause" class="btn-warning"-->
@@ -106,20 +109,18 @@
<field name='is_delivery' invisible="1"/> <field name='is_delivery' invisible="1"/>
<!-- 工单form页面的开始停工按钮等 --> <!-- 工单form页面的开始停工按钮等 -->
<button name="button_start" type="object" string="开始" class="btn-success" <button name="button_start" type="object" string="开始" class="btn-success"
attrs="{'invisible': ['|', '|', '|', '|','|', ('production_state','in', ('draft', 'done', attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','ready')]}"
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')),
('is_user_working', '!=', False),('user_permissions','=',False), ('routing_type', '=', 'CNC加工')]}"
groups="sf_base.group_sf_mrp_user"/> groups="sf_base.group_sf_mrp_user"/>
<button name="button_pending" type="object" string="暂停" class="btn-warning" <button name="button_pending" type="object" string="暂停" class="btn-warning"
groups="sf_base.group_sf_mrp_user" attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"/> groups="sf_base.group_sf_mrp_user"/>
<button name="button_finish" type="object" string="完成" class="btn-success" <button name="button_finish" type="object" string="完成" class="btn-success"
groups="sf_base.group_sf_mrp_user" attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"/> groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/>
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工" <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工"
context="{'default_workcenter_id': workcenter_id}" class="btn-danger" context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
groups="sf_base.group_sf_mrp_user" groups="sf_base.group_sf_mrp_user"
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" <button name="button_unblock" type="object" string="Unblock"
context="{'default_workcenter_id': workcenter_id}" class="btn-danger" context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
groups="sf_base.group_sf_mrp_user" groups="sf_base.group_sf_mrp_user"
@@ -184,10 +185,10 @@
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="functional_fixture_type_id" <field name="functional_fixture_type_id"
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> 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)]}"/> attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" 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>
<!-- <group>--> <!-- <group>-->
<!-- <div>--> <!-- <div>-->
@@ -209,12 +210,12 @@
<field name="programming_state" readonly="1" <field name="programming_state" readonly="1"
attrs='{"invisible": [("programming_no","=",False)]}'/> attrs='{"invisible": [("programming_no","=",False)]}'/>
</group> </group>
<group> <!-- <group>-->
<div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap"> <!-- <div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">-->
<button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码" <!-- <button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码"-->
/> <!-- />-->
</div> <!-- </div>-->
</group> <!-- </group>-->
</page> </page>
</xpath> </xpath>
<!-- <page string="Components" name="components">--> <!-- <page string="Components" name="components">-->
@@ -242,6 +243,7 @@
<!-- </page>--> <!-- </page>-->
<page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'> <page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
<group> <group>
<field name="_barcode_scanned" widget="barcode_handler"/>
<group string="卡盘"> <group string="卡盘">
<field name="chuck_serial_number"/> <field name="chuck_serial_number"/>
<field name="chuck_name"/> <field name="chuck_name"/>
@@ -250,7 +252,6 @@
<field name="chuck_model_id"/> <field name="chuck_model_id"/>
</group> </group>
<group string="托盘"> <group string="托盘">
<field name="_barcode_scanned" widget="barcode_handler"/>
<field name="tray_serial_number" readonly="1" string="序列号"/> <field name="tray_serial_number" readonly="1" string="序列号"/>
<field name="tray_product_id" readonly="1" string="名称"/> <field name="tray_product_id" readonly="1" string="名称"/>
<field name="tray_brand_id" readonly="1" string="品牌"/> <field name="tray_brand_id" readonly="1" string="品牌"/>
@@ -407,8 +408,11 @@
</div> </div>
<div class="col-12 col-lg-6 o_setting_box"> <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="计算定位" <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> </div>
<group> <group>
@@ -421,8 +425,10 @@
<tree editable="bottom"> <tree editable="bottom">
<field name="production_id" invisible="1"/> <field name="production_id" invisible="1"/>
<field name="workpiece_code"/> <field name="workpiece_code"/>
<field name="feeder_station_start" force_save="1"/> <field name="route_id" options="{'no_create': True}"/>
<field name="feeder_station_destination" force_save="1"/> <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="production_line_id"/>
<field name="task_delivery_time" readonly="1"/> <field name="task_delivery_time" readonly="1"/>
<field name="task_completion_time" readonly="1"/> <field name="task_completion_time" readonly="1"/>
@@ -437,16 +443,17 @@
<field name="results" invisible="1"/> <field name="results" invisible="1"/>
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<group> <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="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}' <field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
widget="pdf_viewer"/> widget="pdf_viewer"/>
</group> </group>
<div class="col-12 col-lg-6 o_setting_box"> <!-- <div class="col-12 col-lg-6 o_setting_box">-->
<button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder" <!-- <button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"-->
string="检测确认" <!-- string="检测确认"-->
attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/> <!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
</div> <!-- </div>-->
</page> </page>
</xpath> </xpath>
<xpath expr="//page[1]" position="before"> <xpath expr="//page[1]" position="before">
@@ -476,9 +483,19 @@
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'> <page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
<field name="cmm_ids" widget="one2many" string="CMM程序"> <field name="cmm_ids" widget="one2many" string="CMM程序">
<tree> <tree>
<field name="program_path"/> <field name="sequence_number"/>
<field name="program_date"/> <field name="program_name"/>
<field name="post_processing_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> </tree>
</field> </field>
</page> </page>
@@ -510,6 +527,8 @@
<field name="is_ok"/> <field name="is_ok"/>
<field name="processing_user_id"/> <field name="processing_user_id"/>
<field name="inspection_user_id"/> <field name="inspection_user_id"/>
<field name="save_name" widget="CopyClipboardChar"
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
</xpath> </xpath>
</field> </field>
</record> </record>
@@ -540,7 +559,7 @@
<field name="name">工件配送</field> <field name="name">工件配送</field>
<field name="model">sf.workpiece.delivery</field> <field name="model">sf.workpiece.delivery</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<tree string="工件配送"> <tree string="工件配送" editable="bottom" class="center" create="0" delete="0">
<header> <header>
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/> <button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
</header> </header>
@@ -550,11 +569,13 @@
decoration-danger="status == '待配送'"/> decoration-danger="status == '待配送'"/>
<field name="production_id" string="工件编码"/> <field name="production_id" string="工件编码"/>
<field name="workpiece_code"/> <field name="workpiece_code"/>
<field name="production_line_id"/> <field name="production_line_id" options="{'no_create': True}"/>
<field name="feeder_station_start"/> <field name="route_id" options="{'no_create': True}"/>
<field name="feeder_station_destination"/> <field name="feeder_station_start_id" readonly="1" force_save="1"/>
<field name="task_delivery_time"/> <field name="feeder_station_destination_id" readonly="1" force_save="1"/>
<field name="task_completion_time"/> <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"/> <field name="delivery_duration" widget="float_time"/>
</tree> </tree>
</field> </field>
@@ -567,16 +588,19 @@
<search string="工件配送"> <search string="工件配送">
<field name="production_id"/> <field name="production_id"/>
<field name="workpiece_code"/> <field name="workpiece_code"/>
<field name="feeder_station_start"/> <field name="feeder_station_start_id"/>
<field name="production_line_id"/> <field name="production_line_id"/>
<field name="task_delivery_time"/> <field name="task_delivery_time"/>
<field name="feeder_station_destination"/> <field name="feeder_station_destination_id"/>
<field name="task_completion_time"/> <field name="task_completion_time"/>
<field name="delivery_duration"/> <field name="delivery_duration"/>
<field name="status"/> <field name="status"/>
<searchpanel> <searchpanel>
<field name="production_line_id" icon="fa-building" enable_counters="1"/> <field name="production_line_id" icon="fa-building" enable_counters="1"/>
<field name="status" 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> </searchpanel>
</search> </search>
</field> </field>

View File

@@ -1,13 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<odoo> <odoo>
设备增加刀具库位table <!-- 设备增加刀具库位table-->
<record id="sf_manufacturing_hr_equipment_view_form" model="ir.ui.view"> <record id="sf_manufacturing_hr_equipment_view_form" model="ir.ui.view">
<field name="name">sf_manufacturing_equipment.form</field> <field name="name">sf_manufacturing_equipment.form</field>
<field name="model">maintenance.equipment</field> <field name="model">maintenance.equipment</field>
<field name="inherit_id" ref="sf_maintenance.sf_hr_equipment_view_form"/> <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"> <xpath expr="//page[@name='sf_equipment']" position="after">
<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" <page string="标准刀库" name="sf_equipment_product_template"
attrs="{'invisible': [('equipment_type', '!=', '机床')]}"> attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
<field name='product_template_ids'> <field name='product_template_ids'>

View File

@@ -13,6 +13,12 @@
<button string="打印二维码" name="print_single_method" type="object" class="btn-primary"/> <button string="打印二维码" name="print_single_method" type="object" class="btn-primary"/>
</header> </header>
</xpath> </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> </field>
</record> </record>
</odoo> </odoo>

View File

@@ -5,14 +5,18 @@
<field name="model">sf.workpiece.delivery.wizard</field> <field name="model">sf.workpiece.delivery.wizard</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group>
<field name="delivery_id" invisible="True"/> <field name="delivery_id" invisible="True"/>
<field name="workorder_id" invisible="True"/> <field name="workorder_id" invisible="True"/>
<field name="route_id" required="1" options="{'no_create': True}"/>
</group>
<div> <div>
是否确定配送? <field name="is_ok"/>
确认上述信息正确无误.
</div> </div>
<footer> <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"/> <button string="取消" class="btn btn-secondary" special="cancel"/>
</footer> </footer>
</form> </form>

View File

@@ -11,10 +11,11 @@ class WorkpieceDeliveryWizard(models.TransientModel):
delivery_id = fields.Many2one('sf.workpiece.delivery', string='配送') delivery_id = fields.Many2one('sf.workpiece.delivery', string='配送')
workorder_id = fields.Many2one('mrp.workorder', string='工单') workorder_id = fields.Many2one('mrp.workorder', string='工单')
route_id = fields.Many2one('sf.agv.task.route', '任务路线')
is_ok = fields.Boolean('确认上述信息正确无误.')
def confirm(self): def confirm(self):
if self.workorder_id: if self.workorder_id:
self.workorder_id.workpiece_delivery_ids._delivery_avg() self.workorder_id.workpiece_delivery_ids._delivery_avg()
else: else:
self.delivery_id._delivery_avg() self.delivery_id._delivery_avg()

View File

@@ -44,12 +44,18 @@ class Sf_Mrs_Connect(http.Controller):
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
logging.info('创建cnc工单') logging.info('创建cnc工单')
program_path_tmp = os.path.join('/tmp', ret['folder_name'], 'return', r) 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) files = os.listdir(program_path_tmp)
for f in files: for f in files:
program_path = os.path.join(program_path_tmp, f) program_path = os.path.join(program_path_tmp, f)
logging.info('cnc程序路径 :%s' % program_path) 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['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) return json.JSONEncoder().encode(res)
else: else:
res = {'status': 0, 'message': '该制造订单暂未开始'} res = {'status': 0, 'message': '该制造订单暂未开始'}

View File

@@ -21,14 +21,32 @@ class FtpController():
except Exception: except Exception:
logging.info("ftp连接失败") 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): def download_file_tree(self, target_dir, serverdir):
if not os.path.exists(serverdir): if not os.path.exists(serverdir):
os.makedirs(serverdir) os.makedirs(serverdir)
try: try:
logging.info("进入FTP目录 ") logging.info("进入FTP目录 ")
self.ftp.cwd(target_dir) # 切换工作路径 logging.info('目录:%s' % target_dir)
logging.info('FTP目录:%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() remotenames = self.ftp.nlst()
logging.info('FTP目录文件:%s' % remotenames) logging.info('FTP目录文件:%s' % remotenames)
for file in remotenames: for file in remotenames:
@@ -38,6 +56,9 @@ class FtpController():
return 1 return 1
except Exception: except Exception:
return 0 return 0
finally:
self.ftp.quit()
logging.info("ftp已关闭")
# 下载目录下的检测文件 # 下载目录下的检测文件
def download_reportfile_tree(self, target_dir, serverdir, reportpath): def download_reportfile_tree(self, target_dir, serverdir, reportpath):
@@ -51,6 +72,8 @@ class FtpController():
self.ftp.cwd(target_dir1[1]) # 切换工作路径 self.ftp.cwd(target_dir1[1]) # 切换工作路径
logging.info('目录2:%s' % target_dir1[2]) logging.info('目录2:%s' % target_dir1[2])
self.ftp.cwd(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() remotenames = self.ftp.nlst()
logging.info('FTP目录检测报告文件:%s' % remotenames) logging.info('FTP目录检测报告文件:%s' % remotenames)
for filename in remotenames: for filename in remotenames:

View File

@@ -13,9 +13,13 @@ class ResConfigSettings(models.TransientModel):
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003') token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6') sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com') sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
agv_rcms_url = fields.Char(string='avg_rcms访问地址', agv_rcs_url = fields.Char(string='avg_rcs访问地址',
default='http://IP:PORT/rcms/services/rest/hikRpcService/genAgvSchedulingTask') default='http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask')
agv_rcs_url = fields.Char(string='avg_rcs访问地址', default='http://IP:PORT/xxx/agv/agvCallbackService/agvCallback') 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('特征识别路径') model_parser_url = fields.Char('特征识别路径')
ftp_host = fields.Char(string='FTP的ip') ftp_host = fields.Char(string='FTP的ip')
ftp_port = fields.Char(string='FTP端口') ftp_port = fields.Char(string='FTP端口')
@@ -94,8 +98,10 @@ class ResConfigSettings(models.TransientModel):
token = config.get_param('token', default='') token = config.get_param('token', default='')
sf_secret_key = config.get_param('sf_secret_key', default='') sf_secret_key = config.get_param('sf_secret_key', default='')
sf_url = config.get_param('sf_url', 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='') 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_host = config.get_param('ftp_host', default='')
ftp_port = config.get_param('ftp_port', default='') ftp_port = config.get_param('ftp_port', default='')
ftp_user = config.get_param('ftp_user', default='') ftp_user = config.get_param('ftp_user', default='')
@@ -105,8 +111,10 @@ class ResConfigSettings(models.TransientModel):
token=token, token=token,
sf_secret_key=sf_secret_key, sf_secret_key=sf_secret_key,
sf_url=sf_url, sf_url=sf_url,
agv_rcms_url=agv_rcms_url,
agv_rcs_url=agv_rcs_url, agv_rcs_url=agv_rcs_url,
wbcode=wbcode,
agv_code=agv_code,
center_control_url=center_control_url,
ftp_host=ftp_host, ftp_host=ftp_host,
ftp_port=ftp_port, ftp_port=ftp_port,
ftp_user=ftp_user, ftp_user=ftp_user,
@@ -120,8 +128,10 @@ class ResConfigSettings(models.TransientModel):
ir_config.set_param("token", self.token or "") 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_secret_key", self.sf_secret_key or "")
ir_config.set_param("sf_url", self.sf_url 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("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_host", self.ftp_host or "")
ir_config.set_param("ftp_port", self.ftp_port or "") ir_config.set_param("ftp_port", self.ftp_port or "")
ir_config.set_param("ftp_user", self.ftp_user or "") ir_config.set_param("ftp_user", self.ftp_user or "")

View File

@@ -52,8 +52,6 @@ class MrStaticResourceDataSync(models.Model):
logging.info("夹具型号已每日同步成功") logging.info("夹具型号已每日同步成功")
self.env['sf.fixture.materials.basic.parameters'].sync_fixture_materials_basic_parameters_yesterday() self.env['sf.fixture.materials.basic.parameters'].sync_fixture_materials_basic_parameters_yesterday()
logging.info("夹具型号基本参数已每日同步成功") 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() self.env['sf.functional.fixture.type'].sync_functional_fixture_type_yesterday()
logging.info("功能夹具类型已每日同步成功") logging.info("功能夹具类型已每日同步成功")
self.env['sf.cutting.tool.material'].sync_cutting_tool_material_yesterday() self.env['sf.cutting.tool.material'].sync_cutting_tool_material_yesterday()
@@ -593,6 +591,7 @@ class MachineBrand(models.Model):
if not brand: if not brand:
self.create({ self.create({
"name": item['name'], "name": item['name'],
"active": item['active'],
"code": item['code'], "code": item['code'],
"remark": item['remark'], "remark": item['remark'],
"image_brand": '' if not item['image_brand'] else base64.b64decode(item['image_brand']), "image_brand": '' if not item['image_brand'] else base64.b64decode(item['image_brand']),
@@ -601,6 +600,7 @@ class MachineBrand(models.Model):
}) })
else: else:
brand.name = item['name'] brand.name = item['name']
brand.active = item['active']
brand.remark = item['remark'] brand.remark = item['remark']
brand.image_brand = '' if not item['image_brand'] else base64.b64decode(item['image_brand']) brand.image_brand = '' if not item['image_brand'] else base64.b64decode(item['image_brand'])
brand.tag_ids = self.env['sf.machine.brand.tags'].search( brand.tag_ids = self.env['sf.machine.brand.tags'].search(
@@ -1952,10 +1952,7 @@ class CuttingSpeed(models.Model):
'active': item['active'], 'active': item['active'],
}) })
else: else:
if item['active'] is False: cutting_speed.write({
item.write({'active': False})
else:
self.write({
'execution_standard_id': self.env['sf.international.standards'].search( 'execution_standard_id': self.env['sf.international.standards'].search(
[('code', '=', item['execution_standard_code'])]).id, [('code', '=', item['execution_standard_code'])]).id,
'material_name_id': self.env['sf.materials.model'].search( 'material_name_id': self.env['sf.materials.model'].search(
@@ -1969,7 +1966,8 @@ class CuttingSpeed(models.Model):
'tensile_strength': item['tensile_strength'], 'tensile_strength': item['tensile_strength'],
'hardness': item['hardness'], 'hardness': item['hardness'],
'cutting_speed': item['cutting_speed'], 'cutting_speed': item['cutting_speed'],
'application': item['application'], }) 'application': item['application'],
'active': item['active']})
else: else:
raise ValidationError("切削速度认证未通过") raise ValidationError("切削速度认证未通过")
@@ -2006,10 +2004,7 @@ class CuttingSpeed(models.Model):
'active': item['active'], 'active': item['active'],
}) })
else: else:
if item['active'] is False: cutting_speed.write({
item.write({'active': False})
else:
self.write({
'execution_standard_id': self.env['sf.international.standards'].search( 'execution_standard_id': self.env['sf.international.standards'].search(
[('code', '=', item['execution_standard_code'])]).id, [('code', '=', item['execution_standard_code'])]).id,
'material_name_id': self.env['sf.materials.model'].search( 'material_name_id': self.env['sf.materials.model'].search(
@@ -2023,7 +2018,8 @@ class CuttingSpeed(models.Model):
'tensile_strength': item['tensile_strength'], 'tensile_strength': item['tensile_strength'],
'hardness': item['hardness'], 'hardness': item['hardness'],
'cutting_speed': item['cutting_speed'], 'cutting_speed': item['cutting_speed'],
'application': item['application'], }) 'application': item['application'],
'active': item['active']})
else: else:
raise ValidationError("切削速度认证未通过") raise ValidationError("切削速度认证未通过")
@@ -2098,16 +2094,14 @@ class CuttingSpeed(models.Model):
'active': item['active'], 'active': item['active'],
}) })
else: else:
if item['active'] is False: feed_per_tooth.write({
item.write({'active': False})
else:
self.write({
'materials_type_id': self.env['sf.materials.model'].search( 'materials_type_id': self.env['sf.materials.model'].search(
[('materials_no', '=', item['materials_type_code'])]).id, [('materials_no', '=', item['materials_type_code'])]).id,
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search( 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
[('name', '=', item['cutting_width_depth'])]).id, [('name', '=', item['cutting_width_depth'])]).id,
'blade_diameter': item['blade_diameter'], 'blade_diameter': item['blade_diameter'],
'feed_per_tooth': item['feed_per_tooth'], }) 'feed_per_tooth': item['feed_per_tooth'],
'active': item['active']})
else: else:
raise ValidationError("每齿走刀量认证未通过") raise ValidationError("每齿走刀量认证未通过")
@@ -2136,16 +2130,14 @@ class CuttingSpeed(models.Model):
'active': item['active'], 'active': item['active'],
}) })
else: else:
if item['active'] is False: feed_per_tooth.write({
item.write({'active': False})
else:
self.write({
'materials_type_id': self.env['sf.materials.model'].search( 'materials_type_id': self.env['sf.materials.model'].search(
[('materials_no', '=', item['materials_type_code'])]).id, [('materials_no', '=', item['materials_type_code'])]).id,
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search( 'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
[('name', '=', item['cutting_width_depth'])]).id, [('name', '=', item['cutting_width_depth'])]).id,
'blade_diameter': item['blade_diameter'], 'blade_diameter': item['blade_diameter'],
'feed_per_tooth': item['feed_per_tooth'], }) 'feed_per_tooth': item['feed_per_tooth'],
'active': item['active']})
else: else:
raise ValidationError("每齿走刀量认证未通过") raise ValidationError("每齿走刀量认证未通过")
@@ -2383,6 +2375,7 @@ class CuttingToolBasicParameters(models.Model):
r = requests.post(strUrl, json={}, data=None, headers=headers) r = requests.post(strUrl, json={}, data=None, headers=headers)
r = r.json() r = r.json()
result = json.loads(r['result']) result = json.loads(r['result'])
logging.info(result)
if result['status'] == 1: if result['status'] == 1:
if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_all_list']: 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']: 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'], 'active': integral_tool_item['active'],
}) })
else: else:
self.write({ self.search([('code', '=', integral_tool_item['code'])]).write({
'name': integral_tool_item['name'], 'name': integral_tool_item['name'],
'total_length': integral_tool_item['total_length'], 'total_length': integral_tool_item['total_length'],
'blade_diameter': integral_tool_item['blade_diameter'], 'blade_diameter': integral_tool_item['blade_diameter'],
@@ -2482,7 +2475,7 @@ class CuttingToolBasicParameters(models.Model):
'active': blade_item['active'], 'active': blade_item['active'],
}) })
else: else:
self.write({ self.search([('code', '=', blade_item['code'])]).write({
'name': blade_item['name'], 'name': blade_item['name'],
'length': blade_item['length'], 'length': blade_item['length'],
'thickness': blade_item['thickness'], 'thickness': blade_item['thickness'],
@@ -2539,7 +2532,7 @@ class CuttingToolBasicParameters(models.Model):
'active': chuck_item['active'], 'active': chuck_item['active'],
}) })
else: else:
self.write({ self.search([('code', '=', chuck_item['code'])]).write({
'name': chuck_item['name'], 'name': chuck_item['name'],
'er_size_model': chuck_item['size_model'], 'er_size_model': chuck_item['size_model'],
'min_clamping_diameter': chuck_item['clamping_diameter_min'], 'min_clamping_diameter': chuck_item['clamping_diameter_min'],
@@ -2598,7 +2591,7 @@ class CuttingToolBasicParameters(models.Model):
'active': cutter_arbor_item['active'], 'active': cutter_arbor_item['active'],
}) })
else: else:
self.write({ self.search([('code', '=', cutter_arbor_item['code'])]).write({
'name': cutter_arbor_item['name'], 'name': cutter_arbor_item['name'],
'height': cutter_arbor_item['height'], 'height': cutter_arbor_item['height'],
'width': cutter_arbor_item['width'], 'width': cutter_arbor_item['width'],
@@ -2662,7 +2655,7 @@ class CuttingToolBasicParameters(models.Model):
'active': cutter_head_item['active'], 'active': cutter_head_item['active'],
}) })
else: else:
self.write({ self.search([('code', '=', cutter_head_item['code'])]).write({
'name': cutter_head_item['name'], 'name': cutter_head_item['name'],
'install_blade_tip_num': cutter_head_item['number_blade_installed'], 'install_blade_tip_num': cutter_head_item['number_blade_installed'],
'blade_diameter': cutter_head_item['blade_diameter'], 'blade_diameter': cutter_head_item['blade_diameter'],
@@ -2691,57 +2684,38 @@ class CuttingToolBasicParameters(models.Model):
for knife_handle_item in basic_parameters_knife_handle_list: for knife_handle_item in basic_parameters_knife_handle_list:
knife_handle = self.search( knife_handle = self.search(
[('code', '=', knife_handle_item['code']), ('active', 'in', [True, False])]) [('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: if not knife_handle:
self.create({ val['code'] = knife_handle_item['code']
'name': knife_handle_item['name'], val['cutting_tool_type'] = '刀柄'
'code': knife_handle_item['code'], val['standard_library_id'] = self.env['sf.cutting_tool.standard.library'].search(
'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[ [('code', '=', knife_handle_item['standard_library_code'].replace("JKM", result[
'factory_short_name']))]).id, 'factory_short_name']))]).id
'total_length': knife_handle_item['total_length'], self.create(val)
'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'],
})
else: else:
self.write({ self.search([('code', '=', knife_handle_item['code'])]).write(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'],
'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: else:
raise ValidationError("刀具物料基本参数认证未通过") raise ValidationError("刀具物料基本参数认证未通过")
@@ -2790,10 +2764,7 @@ class CuttingToolBasicParameters(models.Model):
'active': integral_tool_item['active'], 'active': integral_tool_item['active'],
}) })
else: else:
if integral_tool_item['active'] is False: integral_tool.write({
integral_tool.write({'active': False})
else:
self.write({
'name': integral_tool_item['name'], 'name': integral_tool_item['name'],
'total_length': integral_tool_item['total_length'], 'total_length': integral_tool_item['total_length'],
'blade_diameter': integral_tool_item['blade_diameter'], 'blade_diameter': integral_tool_item['blade_diameter'],
@@ -2854,10 +2825,7 @@ class CuttingToolBasicParameters(models.Model):
'active': blade_item['active'], 'active': blade_item['active'],
}) })
else: else:
if blade_item['active'] is False: blade.write({
blade.write({'active': False})
else:
self.write({
'name': blade_item['name'], 'name': blade_item['name'],
'length': blade_item['length'], 'length': blade_item['length'],
'thickness': blade_item['thickness'], 'thickness': blade_item['thickness'],
@@ -2882,6 +2850,7 @@ class CuttingToolBasicParameters(models.Model):
'blade_tip_height_tolerance': blade_item['tip_height_tolerance'], 'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'], 'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
'thickness_tolerance': blade_item['thickness_tolerance'], 'thickness_tolerance': blade_item['thickness_tolerance'],
'active': blade_item['active']
}) })
if 'basic_parameters_chuck' in result['cutting_tool_basic_parameters_yesterday_list']: if 'basic_parameters_chuck' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_chuck']: if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_chuck']:
@@ -2913,10 +2882,7 @@ class CuttingToolBasicParameters(models.Model):
'active': chuck_item['active'], 'active': chuck_item['active'],
}) })
else: else:
if chuck_item['active'] is False: chuck.write({
chuck.write({'active': False})
else:
self.write({
'name': chuck_item['name'], 'name': chuck_item['name'],
'er_size_model': chuck_item['size_model'], 'er_size_model': chuck_item['size_model'],
'min_clamping_diameter': chuck_item['clamping_diameter_min'], 'min_clamping_diameter': chuck_item['clamping_diameter_min'],
@@ -2930,6 +2896,7 @@ class CuttingToolBasicParameters(models.Model):
'weight': chuck_item['weight'], 'weight': chuck_item['weight'],
'max_load_capacity': chuck_item['load_capacity_max'], 'max_load_capacity': chuck_item['load_capacity_max'],
'cooling_jacket': chuck_item['cooling_sleeve_model'], '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 'basic_parameters_cutter_arbor' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_arbor']: if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_arbor']:
@@ -2974,10 +2941,7 @@ class CuttingToolBasicParameters(models.Model):
'active': cutter_arbor_item['active'], 'active': cutter_arbor_item['active'],
}) })
else: else:
if cutter_arbor_item['active'] is False: cutter_arbor.write({
cutter_arbor.write({'active': False})
else:
self.write({
'name': cutter_arbor_item['name'], 'name': cutter_arbor_item['name'],
'height': cutter_arbor_item['height'], 'height': cutter_arbor_item['height'],
'width': cutter_arbor_item['width'], 'width': cutter_arbor_item['width'],
@@ -3005,6 +2969,7 @@ class CuttingToolBasicParameters(models.Model):
'pressing_plate': cutter_arbor_item['fit_plate_model'], 'pressing_plate': cutter_arbor_item['fit_plate_model'],
'screw': cutter_arbor_item['fit_screw_model'], 'screw': cutter_arbor_item['fit_screw_model'],
'spanner': cutter_arbor_item['fit_wrench_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 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']: if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']:
@@ -3042,10 +3007,7 @@ class CuttingToolBasicParameters(models.Model):
'active': cutter_head_item['active'], 'active': cutter_head_item['active'],
}) })
else: else:
if cutter_head_item['active'] is False: cutter_head.write({
cutter_head.write({'active': False})
else:
self.write({
'name': cutter_head_item['name'], 'name': cutter_head_item['name'],
'install_blade_tip_num': cutter_head_item['number_blade_installed'], 'install_blade_tip_num': cutter_head_item['number_blade_installed'],
'blade_diameter': cutter_head_item['blade_diameter'], 'blade_diameter': cutter_head_item['blade_diameter'],
@@ -3065,6 +3027,7 @@ class CuttingToolBasicParameters(models.Model):
'spanner': cutter_head_item['fit_wrench_model'], 'spanner': cutter_head_item['fit_wrench_model'],
'is_cooling_hole': cutter_head_item['is_cooling_hole'], 'is_cooling_hole': cutter_head_item['is_cooling_hole'],
'locating_slot_code': cutter_head_item['locator_slot_code'], '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 'basic_parameters_knife_handle' in result['cutting_tool_basic_parameters_yesterday_list']:
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_knife_handle']: if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_knife_handle']:
@@ -3097,16 +3060,14 @@ class CuttingToolBasicParameters(models.Model):
'cooling_model': knife_handle_item['cooling_model'], 'cooling_model': knife_handle_item['cooling_model'],
'is_quick_cutting': knife_handle_item['is_quick_cutting'], 'is_quick_cutting': knife_handle_item['is_quick_cutting'],
'is_safe_lock': knife_handle_item['is_safe_lock'], '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'], 'screw': knife_handle_item['fit_wrench_model'],
'nut': knife_handle_item['fit_nut_model'], 'nut': knife_handle_item['fit_nut_model'],
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'], 'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
'active': knife_handle_item['active'], 'active': knife_handle_item['active'],
}) })
else: else:
if knife_handle_item['active'] is False: knife_handle.write({
knife_handle.write({'active': False})
else:
self.write({
'name': knife_handle_item['name'], 'name': knife_handle_item['name'],
'total_length': knife_handle_item['total_length'], 'total_length': knife_handle_item['total_length'],
'taper_shank_model': knife_handle_item['taper_shank_model'], 'taper_shank_model': knife_handle_item['taper_shank_model'],
@@ -3121,11 +3082,13 @@ class CuttingToolBasicParameters(models.Model):
'max_rotate_speed': knife_handle_item['rotate_speed_max'], 'max_rotate_speed': knife_handle_item['rotate_speed_max'],
'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'], 'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
'cooling_model': knife_handle_item['cooling_model'], '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_quick_cutting': knife_handle_item['is_quick_cutting'],
'is_safe_lock': knife_handle_item['is_safe_lock'], 'is_safe_lock': knife_handle_item['is_safe_lock'],
'screw': knife_handle_item['fit_wrench_model'], 'screw': knife_handle_item['fit_wrench_model'],
'nut': knife_handle_item['fit_nut_model'], 'nut': knife_handle_item['fit_nut_model'],
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'], 'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
'active': knife_handle_item['active']
}) })
else: else:
raise ValidationError("刀具物料基本参数认证未通过") raise ValidationError("刀具物料基本参数认证未通过")

View File

@@ -81,12 +81,30 @@
<div class="o_setting_left_pane"/> <div class="o_setting_left_pane"/>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<div class="text-muted"> <div class="text-muted">
<label for="agv_rcms_url" string="调度系统(cms)访问地址"/> <label for="agv_rcs_url" string="访问地址"/>
<field name="agv_rcms_url"/> <field name="agv_rcs_url"/>
</div> </div>
<div class="text-muted"> <div class="text-muted">
<label for="agv_rcs_url" string="RCS-2000系统访问地址"/> <label for="agv_code" string="车辆编号"/>
<field name="agv_rcs_url"/> <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> </div>
</div> </div>

View File

@@ -71,7 +71,7 @@
<field name="order_deadline"/> <field name="order_deadline"/>
<!-- <field name="process_time"/> --> <!-- <field name="process_time"/> -->
<field name="schedule_setting"/> <field name="schedule_setting"/>
<field name="production_line_id"/> <field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
<!-- Chatter --> <!-- Chatter -->

View File

@@ -6,7 +6,7 @@
<field name="arch" type="xml"> <field name="arch" type="xml">
<form> <form>
<group> <group>
<field name="production_line_id"/> <field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
</group> </group>
<footer> <footer>
<button string="确认排程" name="action_plan_all" type="object" class="btn-primary"/> <button string="确认排程" name="action_plan_all" type="object" class="btn-primary"/>

View File

@@ -19,7 +19,10 @@ class QualityCheck(models.Model):
# headers = Common.get_headers(self, token, sf_secret_key) # headers = Common.get_headers(self, token, sf_secret_key)
headers = {'Authorization': 'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A'} headers = {'Authorization': 'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A'}
crea_url = "https://x24467i973.zicp.fun/AutoDeviceApi/PartSpecProc" 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) r = requests.post(crea_url, json=val, headers=headers)
ret = r.json() ret = r.json()
logging.info('_register_quality_check:%s' % ret) logging.info('_register_quality_check:%s' % ret)
@@ -33,4 +36,5 @@ class QualityCheck(models.Model):
'quality_state': 'fail', 'quality_state': 'fail',
'user_id': self.env.user.id, 'user_id': self.env.user.id,
'control_date': datetime.now()}) 'control_date': datetime.now()})
if self.picking_id and 'WH/MO/' in self.picking_id.origin:
self._register_quality_check() self._register_quality_check()

View File

@@ -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,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_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_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_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 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 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
43 access_product_template_group_plan_director access_product_template_group_sf_tool_user product_template_group_plan_director product_template_group_sf_tool_user product.model_product_template sf_base.group_plan_director sf_base.group_sf_tool_user 1 0 0 0
44 access_product_template_group_sf_equipment_user access_product_template_group_sf_order_user product_template_group_sf_equipment_user product_template_group_sf_order_user product.model_product_template sf_base.group_sf_equipment_user sf_base.group_sf_order_user 1 0 0 0
45 access_product_template_group_sf_tool_user access_product_template_group_sf_mrp_manager product_template_group_sf_tool_user product_template_group_sf_mrp_manager product.model_product_template sf_base.group_sf_tool_user sf_base.group_sf_mrp_manager 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
access_product_template_group_sf_mrp_manager product_template_group_sf_mrp_manager product.model_product_template sf_base.group_sf_mrp_manager 1 0 0 0
46 access_product_template_group_equipment_user product_template_group_equipment_user product.model_product_template sf_maintenance.sf_group_equipment_user 1 0 0 0
47 access_product_template_group_equipment_manager product_template_group_equipment_manager product.model_product_template sf_maintenance.sf_group_equipment_manager 1 0 0 0
48 access_quality_alert_stage_group_quality quality_alert_stage_group_quality quality.model_quality_alert_stage sf_base.group_quality 1 0 0 0

View File

@@ -1,5 +1,6 @@
from . import sale_order 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 auto_quatotion_common
from . import parser_and_calculate_work_time from . import parser_and_calculate_work_time
from . import preload_datas_functions from . import preload_datas_functions

View File

@@ -2,7 +2,7 @@
import logging import logging
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from odoo import fields, models, api 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' __author__ = 'jinling.yang'
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View File

@@ -8,8 +8,8 @@ from datetime import datetime
import requests import requests
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
from OCC.Extend.DataExchange import read_step_file # from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file # from OCC.Extend.DataExchange import write_stl_file
from odoo import models, fields, api from odoo import models, fields, api
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from odoo.exceptions import ValidationError, UserError from odoo.exceptions import ValidationError, UserError

View 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("模型上色失败")

View File

@@ -1,5 +1,6 @@
import datetime import datetime
import base64 import base64
from odoo import Command
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from odoo.exceptions import UserError, ValidationError from odoo.exceptions import UserError, ValidationError
@@ -84,11 +85,19 @@ class ReSaleOrder(models.Model):
self.check_status = 'pending' self.check_status = 'pending'
def get_customer(self): 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') customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc')
if customer: 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 return customer
else: 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 return partner
# 业务平台分配工厂时在创建完产品后再创建销售明细信息 # 业务平台分配工厂时在创建完产品后再创建销售明细信息
@@ -133,6 +142,12 @@ class ResaleOrderLine(models.Model):
check_status = fields.Selection(related='order_id.check_status') 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): class RePurchaseOrder(models.Model):
_inherit = 'purchase.order' _inherit = 'purchase.order'
@@ -197,6 +212,16 @@ class RePurchaseOrder(models.Model):
order.message_subscribe([order.partner_id.id]) order.message_subscribe([order.partner_id.id])
return True 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): class ResPartnerToSale(models.Model):
_inherit = 'res.partner' _inherit = 'res.partner'

View File

@@ -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_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,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_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_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_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 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_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_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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
14 access_product_product_group_sale_director product_product_group_sale_director product.model_product_product sf_base.group_sale_director 1 1 1 0
15 access_product_product_group_purchase product_product_group_purchase product.model_product_product sf_base.group_purchase 1 0 0 0
16 access_product_product_group_purchase_director product_product_group_purchase_director product.model_product_product sf_base.group_purchase_director 1 1 1 0
17 access_product_product_group_plan_dispatch product_product_group_plan_dispatch product.model_product_product sf_base.group_plan_dispatch 1 0 0 0
18 access_product_product_group_plan_director product_product_group_plan_director product.model_product_product sf_base.group_plan_director 1 1 1 0
19 access_product_template_group_sale_salemanager product_template_group_sale_salemanager product.model_product_template sf_base.group_sale_salemanager 1 0 0 0
20 access_product_template_group_sale_director product_template_group_sale_director product.model_product_template sf_base.group_sale_director 1 1 1 0
21 access_product_template_group_purchase product_template_group_purchase product.model_product_template sf_base.group_purchase 1 0 0 0
92 access_product_category_group_purchase_director product.category group_purchase_director product.model_product_category sf_base.group_purchase_director 1 1 1 0
93 access_product_supplierinfo_group_plan_director product.supplierinfo user product.model_product_supplierinfo sf_base.group_plan_director 1 1 1 0
94 access_product_category_group_plan_director product.category user product.model_product_category sf_base.group_plan_director 1 1 1 0
95
96
97
98
99
100

View File

@@ -47,17 +47,8 @@
</h1> </h1>
<group> <group>
<group> <group>
<field name="customer_id" /> <field name="customer_id" context="{'is_customer': True }"
<field name="material_id"/> options="{'no_create': True}" required="1"/>
<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="upload_model_file" widget="many2many_binary"/> <field name="upload_model_file" widget="many2many_binary"/>
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1" <field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
attrs="{'invisible': [('model_file', '=', False)]}"/> attrs="{'invisible': [('model_file', '=', False)]}"/>
@@ -75,8 +66,18 @@
<field name="model_height" class="o_address_zip" <field name="model_height" class="o_address_zip"
options="{'format': false}"/> options="{'format': false}"/>
</div> </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="processing_time"/>
<field name="quantity" options="{'format': false}"/>
<field name="unit_price"/>
<field name="price" options="{'format': false}"/>
</group> </group>
</group> </group>
</sheet> </sheet>

View File

@@ -26,7 +26,7 @@
</field> </field>
<field name="email" position="replace"> <field name="email" position="replace">
<field name="email" <field name="email"
attrs="{'required' : [('customer_rank','>', 0)],'readonly': [('id','!=', False)]}"/> attrs="{'readonly': [('id','!=', False)]}"/>
</field> </field>
<field name="mobile" position="attributes"> <field name="mobile" position="attributes">
<attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]} <attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}
@@ -37,19 +37,19 @@
</attribute> </attribute>
</field> </field>
<field name="street" position="attributes"> <field name="street" position="attributes">
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} <attribute name="attrs">{'readonly': [('id','!=', False)]}
</attribute> </attribute>
</field> </field>
<field name="street2" position="attributes"> <field name="street2" position="attributes">
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} <attribute name="attrs">{'readonly': [('id','!=', False)]}
</attribute> </attribute>
</field> </field>
<field name="city" position="attributes"> <field name="city" position="attributes">
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} <attribute name="attrs">{'readonly': [('id','!=', False)]}
</attribute> </attribute>
</field> </field>
<field name="country_id" position="attributes"> <field name="country_id" position="attributes">
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} <attribute name="attrs">{'readonly': [('id','!=', False)]}
</attribute> </attribute>
</field> </field>
<xpath expr="//group[@name='sale']/field[@name='user_id']" position="replace"> <xpath expr="//group[@name='sale']/field[@name='user_id']" position="replace">

View File

@@ -103,7 +103,7 @@
<!-- </xpath>--> <!-- </xpath>-->
<field name="partner_id" position="replace"> <field name="partner_id" position="replace">
<field name="partner_id" widget="res_partner_many2one" context="{'is_customer': True }" <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>
<field name="payment_term_id" position="attributes"> <field name="payment_term_id" position="attributes">
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute> <attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>

View File

@@ -16,11 +16,13 @@
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'wizard/wizard_view.xml', 'wizard/wizard_view.xml',
'views/tool_base_views.xml', 'views/tool_base_views.xml',
'views/functional_tool_views.xml',
'views/mrp_workcenter_views.xml', 'views/mrp_workcenter_views.xml',
'views/sf_maintenance_equipment.xml', 'views/sf_maintenance_equipment.xml',
'views/menu_view.xml', 'views/menu_view.xml',
'views/tool_material_search.xml', 'views/tool_material_search.xml',
'views/fixture_material_search_views.xml', 'views/fixture_material_search_views.xml',
'data/tool_data.xml',
], ],
'demo': [ 'demo': [
], ],

View File

@@ -22,14 +22,14 @@ class Manufacturing_Connect(http.Controller):
ret = json.loads(datas) ret = json.loads(datas)
# ret = json.loads(ret['result']) # ret = json.loads(ret['result'])
logging.info('DeviceId:%s' % ret) 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': []} res = {'Succeed': True, 'Datas': []}
if functional_tools: if functional_tools:
for item in functional_tools: for item in functional_tools:
res['Datas'].append({ res['Datas'].append({
'GroupName': item.tool_groups_id.name, 'GroupName': item.tool_groups_id.name,
'ToolId': item.code, 'ToolId': item.functional_cutting_tool_model_id.name,
'ToolName': item.name 'ToolName': item.name
}) })
except Exception as e: except Exception as e:

View File

@@ -1,8 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<odoo> <odoo>
<data> <record model="ir.cron" id="ir_cron_sf_tool_datasync">
<!-- <record model="sf.machine.table.tool.changing.apply" id="sf_create_tool_change_application">--> <field name="name">定时同步刀具物料、功能刀具信息到cloud</field>
<field name="model_id" ref="model_sf_tool_datasync"/>
<!-- </record>--> <field name="state">code</field>
</data> <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> </odoo>

View File

@@ -1,4 +1,5 @@
from . import base from . import base
from . import functional_tool
from . import tool_material_search from . import tool_material_search
from . import maintenance_equipment from . import maintenance_equipment
from . import mrp_workorder from . import mrp_workorder

View File

@@ -1,483 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re import logging
import json
import requests
from datetime import timedelta from datetime import timedelta
from odoo import SUPERUSER_ID from odoo import SUPERUSER_ID
from odoo import fields, models, api from odoo import fields, models, api
from odoo.exceptions import ValidationError 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): class MachineTableToolChangingApply(models.Model):
@@ -502,7 +29,7 @@ class MachineTableToolChangingApply(models.Model):
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', store=True, barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', store=True,
domain=[('product_id.name', '=', '功能刀具')], domain=[('product_id.name', '=', '功能刀具')],
related='functional_tool_name_id.barcode_id') 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')], functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', domain=[('assemble_status', '=', '1')],
string='功能刀具名称') string='功能刀具名称')
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True, 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='机床名称', machine_table_name_id = fields.Many2one('maintenance.equipment', string='机床名称',
domain="[('production_line_id', '=', production_line_id)]") domain="[('production_line_id', '=', production_line_id)]")
machine_table_name = fields.Char(string='机台号', readonly=True, related='machine_table_name_id.name') 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)]") domain="[('equipment_id', '=', machine_table_name_id)]")
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True) whether_standard_knife = fields.Boolean(string='是否标准刀', default=True)
need_knife_time = fields.Datetime(string='用刀时间', readonly=False) need_knife_time = fields.Datetime(string='用刀时间', readonly=False)
@@ -676,19 +203,20 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号',
domain=[('product_id.name', '=', '功能刀具')]) domain=[('product_id.name', '=', '功能刀具')])
functional_tool_name = fields.Char(string='功能刀具名称', compute='_compute_functional_tool_name') functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False) functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组') compute='_compute_tool_number', store=True)
diameter = fields.Integer(string='刀具直径(mm)', readonly=False) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_tool_number', store=True)
tool_included_angle = fields.Float(string='尖R角(mm)', readonly=False) diameter = fields.Integer(string='具直径(mm)', compute='_compute_tool_number', store=True)
tool_loading_length = fields.Float(string='总长度(mm)', readonly=False) 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)') extension_length = fields.Float(string='伸出长(mm)')
effective_length = fields.Float(string='有效长(mm)') effective_length = fields.Float(string='有效长(mm)')
new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=False, default='0') new_former = fields.Selection([('0', ''), ('1', '')], string='新/旧', readonly=False, default='0')
coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], default='3', coarse_middle_thin = fields.Selection([("1", ""), ('2', ''), ('3', '')], default='3',
string='粗/中/精', readonly=False) string='粗/中/精', readonly=False)
L_D = fields.Float(string='L/D值', 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) required_cutting_time = fields.Integer(string='需切削时长', readonly=False)
process_type = fields.Char('加工类型') process_type = fields.Char('加工类型')
margin_x_y = fields.Float('余量_X/Y') margin_x_y = fields.Float('余量_X/Y')
@@ -704,15 +232,24 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
active = fields.Boolean(string='已归档', default=True) active = fields.Boolean(string='已归档', default=True)
@api.depends('diameter', 'tool_included_angle', 'tool_groups_id') @api.depends('functional_tool_name')
def _compute_functional_tool_name(self): def _compute_tool_number(self):
for obj in self: for item in self:
if obj.tool_groups_id: inventory = self.env['sf.tool.inventory'].sudo().search([('name', '=', item.functional_tool_name)])
obj.functional_tool_name = '%s-D%sR%s' % ( if inventory:
obj.tool_groups_id.name, obj.diameter, item.functional_tool_type_id = inventory.functional_cutting_tool_model_id.id
obj.tool_included_angle) 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: 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 @api.model
def _read_group_names(self, categories, domain, order): def _read_group_names(self, categories, domain, order):
@@ -786,10 +323,9 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划 根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
""" """
status = False 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( 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: if functional_tools:
for functional_tool in functional_tools: for functional_tool in functional_tools:
if functional_tool.on_tool_stock_num == 0: if functional_tool.on_tool_stock_num == 0:
@@ -802,7 +338,6 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'name': cnc_processing.workorder_id.production_id.name, 'name': cnc_processing.workorder_id.production_id.name,
'cam_procedure_code': cnc_processing.program_name, 'cam_procedure_code': cnc_processing.program_name,
'filename': cnc_processing.cnc_id.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, 'functional_tool_name': cnc_processing.cutting_tool_name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no, 'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'process_type': cnc_processing.processing_type, 'process_type': cnc_processing.processing_type,
@@ -813,8 +348,11 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'shank_model': cnc_processing.cutting_tool_handle_type, 'shank_model': cnc_processing.cutting_tool_handle_type,
'estimated_processing_time': cnc_processing.estimated_processing_time, 'estimated_processing_time': cnc_processing.estimated_processing_time,
}) })
logging.info('CAM工单程序用刀计划创建成功')
# 创建装刀请求 # 创建装刀请求
knife_plan.apply_for_tooling() knife_plan.apply_for_tooling()
else:
logging.info('功能刀具【%s】满足CNC用刀需求')
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
@@ -825,10 +363,10 @@ class FunctionalToolAssembly(models.Model):
@api.depends('functional_tool_name') @api.depends('functional_tool_name')
def _compute_name(self): def _compute_name(self):
for obj in self: for obj in self:
obj.name = obj.after_assembly_functional_tool_name obj.name = obj.assembly_order_code
code = fields.Char('功能刀具编码', readonly=True) 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) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
name = fields.Char(string='名称', readonly=True, compute='_compute_name') name = fields.Char(string='名称', readonly=True, compute='_compute_name')
assembly_order_code = fields.Char(string='组装单编码', readonly=True) assembly_order_code = fields.Char(string='组装单编码', readonly=True)
@@ -870,56 +408,141 @@ class FunctionalToolAssembly(models.Model):
return categories.browse(functional_tool_type_ids) 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='整体式刀具型号', cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
related='integral_code_id.product_id.cutting_tool_model_id') related='integral_product_id.cutting_tool_model_id')
integral_name = fields.Char('整体式刀具名称', related='integral_code_id.product_id.name')
integral_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='整体式刀具规格', 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='整体式刀具品牌', 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', '刀片序列号', 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')
@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) barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True) after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True)

View 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

View File

@@ -1,9 +1,10 @@
import json import json
import base64 import base64
import requests import requests
import logging
from odoo import models, api from odoo import models, api
from odoo.addons.sf_base.commons.common import Common 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): def get_suitable_machining_method_names(item):
@@ -30,6 +31,30 @@ def get_suitable_coolant_names(item):
return suitable_coolant_names 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): class StockLot(models.Model):
_inherit = 'stock.lot' _inherit = 'stock.lot'
_description = '刀具物料序列号注册' _description = '刀具物料序列号注册'
@@ -40,7 +65,19 @@ class StockLot(models.Model):
sf_secret_key = sf_sync_config['sf_secret_key'] sf_secret_key = sf_sync_config['sf_secret_key']
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create" 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 = [] tool_material_stock_list = []
if objs_all: if objs_all:
for item in objs_all: for item in objs_all:
@@ -57,7 +94,7 @@ class StockLot(models.Model):
if ret.get('code') == 200: if ret.get('code') == 200:
return '刀具物料序列号注册成功' return '刀具物料序列号注册成功'
else: else:
raise UserError("没有注册刀具物料序列号信息") logging.info("没有注册刀具物料序列号信息")
class ToolMaterial(models.Model): class ToolMaterial(models.Model):
@@ -73,6 +110,18 @@ class ToolMaterial(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + self.crea_url str_url = sf_sync_config['sf_url'] + self.crea_url
objs_all = self.search([('id', '=', self.id)]) 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 = [] tool_material_list = []
if objs_all: if objs_all:
for item in objs_all: for item in objs_all:
@@ -95,7 +144,7 @@ class ToolMaterial(models.Model):
if ret.get('code') == 200: if ret.get('code') == 200:
return '刀具物料注册成功' return '刀具物料注册成功'
else: else:
raise UserError("没有注册刀具物料信息") logging.info('没有注册刀具物料信息')
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
@@ -120,6 +169,18 @@ class FunctionalCuttingToolEntity(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + self.crea_url str_url = sf_sync_config['sf_url'] + self.crea_url
objs_all = self.env['sf.functional.cutting.tool.entity'].search([('id', '=', self.id)]) 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 = [] functional_tool_list = []
if objs_all: if objs_all:
for item in objs_all: for item in objs_all:
@@ -170,7 +231,7 @@ class FunctionalCuttingToolEntity(models.Model):
if ret.get('code') == 200: if ret.get('code') == 200:
return "功能刀具注册成功" return "功能刀具注册成功"
else: else:
raise UserError("没有注册功能刀具信息") logging.info('没有注册功能刀具信息')
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
@@ -201,6 +262,18 @@ class FunctionalToolWarning(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + self.crea_url str_url = sf_sync_config['sf_url'] + self.crea_url
objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)]) 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 = [] tool_warning_list = []
if objs_all: if objs_all:
for item in objs_all: for item in objs_all:
@@ -237,7 +310,7 @@ class FunctionalToolWarning(models.Model):
if ret.get('code') == 200: if ret.get('code') == 200:
return "功能刀具预警注册成功" return "功能刀具预警注册成功"
else: else:
raise UserError("没有注册功能刀具预警信息") logging.info('没有注册功能刀具预警信息')
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
@@ -262,6 +335,18 @@ class StockMoveLine(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + self.crea_url 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)]) 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 = [] tool_stock_list = []
if objs_all: if objs_all:
for item in objs_all: for item in objs_all:
@@ -289,7 +374,7 @@ class StockMoveLine(models.Model):
if ret.get('code') == 200: if ret.get('code') == 200:
return "功能刀具出入库记录注册成功" return "功能刀具出入库记录注册成功"
else: else:
raise UserError("没有注册功能刀具出入库记录信息") logging.info('没有注册功能刀具出入库记录信息')
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
@@ -314,6 +399,18 @@ class RealTimeDistributionFunctionalTools(models.Model):
headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
str_url = sf_sync_config['sf_url'] + self.crea_url 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)]) 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 = [] tool_distribution_list = []
if objs_all: if objs_all:
for item in objs_all: for item in objs_all:
@@ -353,7 +450,7 @@ class RealTimeDistributionFunctionalTools(models.Model):
if ret.get('code') == 200: if ret.get('code') == 200:
return "功能刀具出入库记录注册成功" return "功能刀具出入库记录注册成功"
else: else:
raise UserError("没有注册功能刀具出入库记录信息") logging.info('没有注册功能刀具出入库记录信息')
@api.model_create_multi @api.model_create_multi
def create(self, vals_list): def create(self, vals_list):
@@ -362,3 +459,9 @@ class RealTimeDistributionFunctionalTools(models.Model):
if record: if record:
record.enroll_functional_tool_real_time_distribution() record.enroll_functional_tool_real_time_distribution()
return records 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

View File

@@ -36,6 +36,7 @@ class CNCprocessing(models.Model):
obj = super(CNCprocessing, self).create(vals) obj = super(CNCprocessing, self).create(vals)
# 调用CAM工单程序用刀计划创建方法 # 调用CAM工单程序用刀计划创建方法
self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(obj) self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(obj)
logging.info('成功调用CAM工单程序用刀计划创建方法')
return obj return obj

View File

@@ -20,35 +20,35 @@ class ToolMaterial(models.Model):
specification_id = fields.Many2one('sf.tool.materials.basic.parameters', '规格', specification_id = fields.Many2one('sf.tool.materials.basic.parameters', '规格',
related='product_id.specification_id') related='product_id.specification_id')
image = fields.Binary('图片', related='product_id.image_1920') image = fields.Binary('图片', related='product_id.image_1920')
number = fields.Integer('总数量', compute='_compute_number') number = fields.Integer('总数量', compute='_compute_number', store=True)
usable_num = fields.Integer('可用数量', compute='_compute_number') usable_num = fields.Integer('可用数量', compute='_compute_number', store=True)
have_been_used_num = fields.Integer('在用数量', compute='_compute_number') have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True)
scrap_num = fields.Integer('报废数量', compute='_compute_number') scrap_num = fields.Integer('报废数量', compute='_compute_number', store=True)
barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=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): def _compute_number(self):
for record in self: for record in self:
usable_num = 0 usable_num = 0
have_been_used_num = 0 have_been_used_num = 0
scrap_num = 0 scrap_num = 0
if record.barcode_ids: for quant in record.product_id.stock_quant_ids:
record.number = len(record.barcode_ids) location = quant.location_id.name
for barcode_id in record.barcode_ids: if location == '刀具房':
if barcode_id.quant_ids: usable_num += quant.quantity
if barcode_id.quant_ids[-1].location_id.name == '刀具组装位置': elif location == '刀具组装位置':
have_been_used_num = have_been_used_num + 1 have_been_used_num += quant.quantity
else: elif location == '进货':
usable_num = usable_num + 1 pass
elif location != 'Vendors':
scrap_num += quant.quantity
record.usable_num = usable_num record.usable_num = usable_num
record.have_been_used_num = have_been_used_num record.have_been_used_num = have_been_used_num
record.scrap_num = scrap_num record.scrap_num = scrap_num
else: record.number = usable_num + have_been_used_num + scrap_num
record.number = 0 # 更新数据到cloud的动态数据
record.usable_num = 0 record.enroll_tool_material()
record.have_been_used_num = 0
record.scrap_num = 0
@api.model @api.model
def _read_group_cutting_tool_material_id(self, categories, domain, order): def _read_group_cutting_tool_material_id(self, categories, domain, order):

View File

@@ -1,33 +1,33 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink 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_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_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_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_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_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_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_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_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_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_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_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 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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 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_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_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_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_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_group_plan_dispatch sf.tool.change.requirement.information model_sf_tool_change_requirement_information sf_base.group_plan_dispatch 1 0 0 0
3 access_sf_tool_transfer_request_information_group_plan_dispatch access_sf_functional_cutting_tool_entity_group_plan_dispatch sf.tool.transfer.request.information sf.functional.cutting.tool.entity model_sf_tool_transfer_request_information model_sf_functional_cutting_tool_entity sf_base.group_plan_dispatch 1 0 0 0
4 access_sf_functional_tool_warning sf.functional.tool.warning model_sf_functional_tool_warning sf_base.group_sf_tool_user 1 1 1 0
5 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
6 access_sf_functional_tool_assembly_group_plan_dispatch access_sf_real_time_distribution_of_functional_tools sf.functional.tool.assembly sf.real.time.distribution.of.functional.tools model_sf_functional_tool_assembly model_sf_real_time_distribution_of_functional_tools sf_base.group_plan_dispatch sf_base.group_sf_tool_user 1 0 1 0 1 0
7 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
8 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
9 access_sf_functional_tool_assembly_order_group_plan_dispatch access_sf_cam_work_order_program_knife_plan_group_plan_dispatch sf.functional.tool.assembly.order sf.cam.work.order.program.knife.plan model_sf_functional_tool_assembly_order model_sf_cam_work_order_program_knife_plan sf_base.group_plan_dispatch 1 0 0 0
10 access_sf_tool_material_search_group_plan_dispatch access_sf_machine_table_tool_changing_apply sf.tool.material.search sf.machine.table.tool.changing.apply model_sf_tool_material_search model_sf_machine_table_tool_changing_apply sf_base.group_plan_dispatch sf_base.group_sf_tool_user 1 0 1 0 1 0
11 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
12 access_sf_fixture_material_search_group_plan_dispatch access_sf_tool_change_requirement_information sf.fixture.material.search sf.tool.change.requirement.information model_sf_fixture_material_search model_sf_tool_change_requirement_information sf_base.group_plan_dispatch sf_base.group_sf_tool_user 1 0 1 0 1 0
13 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
14 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
15 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
16 access_sf_functional_tool_assembly sf.functional.tool.assembly model_sf_functional_tool_assembly sf_base.group_sf_tool_user 1 1 1 0
17 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
18 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
19 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
20 access_sf_tool_material_search sf.tool.material.search model_sf_tool_material_search sf_base.group_sf_tool_user 1 1 1 0
21 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
22 access_sf_fixture_material_search sf.fixture.material.search model_sf_fixture_material_search sf_base.group_sf_order_user 1 0 0 0
23 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
24
25
26
27
28
29
30
31
32
33

View File

@@ -100,6 +100,6 @@
name="夹具物料查询" name="夹具物料查询"
id="menu_sf_fixture_material_search" id="menu_sf_fixture_material_search"
action="action_sf_fixture_material_search" action="action_sf_fixture_material_search"
parent="menu_sf_tool_manage" parent="menu_sf_fixture"
/> />
</odoo> </odoo>

View 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>

View File

@@ -7,6 +7,13 @@
groups="mrp.group_mrp_routings" groups="mrp.group_mrp_routings"
parent="mrp.menu_mrp_root" parent="mrp.menu_mrp_root"
sequence="20"/> sequence="20"/>
<menuitem id="menu_sf_fixture"
name="夹具管理"
groups="sf_base.group_sf_order_user"
parent="mrp.menu_mrp_root"
sequence="20"/>
<menuitem <menuitem
id="menu_sf_functional_cutting_tool" id="menu_sf_functional_cutting_tool"
parent="menu_sf_tool_manage" parent="menu_sf_tool_manage"

View File

@@ -1,510 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<odoo> <odoo>
<data> <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"> <record id="sf_machine_table_tool_changing_apply_tree" model="ir.ui.view">
<field name="name">机床换刀申请</field> <field name="name">机床换刀申请</field>
@@ -995,7 +491,7 @@
<field name="name">功能刀具组装</field> <field name="name">功能刀具组装</field>
<field name="model">sf.functional.tool.assembly</field> <field name="model">sf.functional.tool.assembly</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form create="0" delete="0"> <form create="0" delete="0" edit="0">
<header> <header>
<button string="组装" <button string="组装"
name="%(sf_tool_management.sf_functional_tool_assembly_order_act)d" name="%(sf_tool_management.sf_functional_tool_assembly_order_act)d"
@@ -1056,7 +552,7 @@
<group> <group>
<group> <group>
<field name="barcode_id" invisible="True"/> <field name="barcode_id" invisible="True"/>
<field name="rfid" string="功能刀具rfid" readonly="false"/> <field name="rfid" string="功能刀具rfid"/>
<field name="code"/> <field name="code"/>
<field name="after_assembly_functional_tool_name" <field name="after_assembly_functional_tool_name"
string="功能刀具名称"/> string="功能刀具名称"/>
@@ -1093,7 +589,6 @@
</group> </group>
</group> </group>
<group> <group>
<group col="1">
<group col="1" attrs="{'invisible': [('handle_code_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('handle_code_id', '=', False)]}">
<div> <div>
<separator string="刀柄:" style="font-size: 13px;"/> <separator string="刀柄:" style="font-size: 13px;"/>
@@ -1101,33 +596,50 @@
<group> <group>
<field name="handle_code_id" string="序列号" placeholder="请选择" <field name="handle_code_id" string="序列号" placeholder="请选择"
options="{'no_create': True, 'no_quick_create': True}"/> options="{'no_create': True, 'no_quick_create': True}"/>
<field name="handle_name" string="名称"/> <field name="handle_freight_rfid" string="Rfid"/>
<field name="handle_product_id" string="名称"/>
<field name="cutting_tool_cutterhandle_model_id" string="型号"/> <field name="cutting_tool_cutterhandle_model_id" string="型号"/>
<field name="handle_specification_id" string="规格"/> <field name="handle_specification_id" string="规格"/>
<field name="sf_tool_brand_id_5" string="品牌"/> <field name="sf_tool_brand_id_5" string="品牌"/>
</group> </group>
</group> </group>
<group col="1" attrs="{'invisible': [('integral_code_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('chuck_freight_barcode', '=', False)]}">
<div>
<separator string="夹头:" style="font-size: 13px;"/>
</div>
<group>
<group>
<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>
</group>
<group>
<group col="1">
<group col="1"
attrs="{'invisible': [('integral_freight_barcode', '=', False)]}">
<div> <div>
<separator string="整体式刀具:" style="font-size: 13px;"/> <separator string="整体式刀具:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<field name="integral_code_id" placeholder="请选择" string="序列号" <field name="integral_freight_barcode" string="货位"/>
options="{'no_create': True, 'no_quick_create': True}"/> <field name="integral_product_id" string="名称"/>
<field name="integral_name" string="名称"/>
<field name="cutting_tool_integral_model_id" string="型号"/> <field name="cutting_tool_integral_model_id" string="型号"/>
<field name="integral_specification_id" string="规格"/> <field name="integral_specification_id" string="规格"/>
<field name="sf_tool_brand_id_1" string="品牌"/> <field name="sf_tool_brand_id_1" string="品牌"/>
</group> </group>
</group> </group>
<group col="1" attrs="{'invisible': [('blade_code_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('blade_freight_barcode', '=', False)]}">
<div> <div>
<separator string="刀片:" style="font-size: 13px;"/> <separator string="刀片:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<field name="blade_code_id" placeholder="请选择" string="序列号" <field name="blade_freight_barcode" string="货位"/>
options="{'no_create': True, 'no_quick_create': True}"/> <field name="blade_product_id" string="名称"/>
<field name="blade_name" string="名称"/>
<field name="cutting_tool_blade_model_id" string="型号"/> <field name="cutting_tool_blade_model_id" string="型号"/>
<field name="blade_specification_id" string="规格"/> <field name="blade_specification_id" string="规格"/>
<field name="sf_tool_brand_id_2" string="品牌"/> <field name="sf_tool_brand_id_2" string="品牌"/>
@@ -1135,45 +647,28 @@
</group> </group>
</group> </group>
<group col="1"> <group col="1">
<group col="1" attrs="{'invisible': [('chuck_code_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('bar_freight_barcode', '=', 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)]}">
<div> <div>
<separator string="刀杆:" style="font-size: 13px;"/> <separator string="刀杆:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="bar_code_id" placeholder="请选择" string="序列号" <field name="bar_freight_barcode" string="货位"/>
options="{'no_create': True, 'no_quick_create': True}"/> <field name="bar_product_id" string="名称"/>
<field name="bar_name" string="名称"/>
<field name="cutting_tool_cutterbar_model_id" string="型号"/> <field name="cutting_tool_cutterbar_model_id" string="型号"/>
<field name="bar_specification_id" string="规格"/> <field name="bar_specification_id" string="规格"/>
<field name="sf_tool_brand_id_3" string="品牌"/> <field name="sf_tool_brand_id_3" string="品牌"/>
</group> </group>
</group> </group>
</group> </group>
<group col="1" attrs="{'invisible': [('pad_code_id', '=', False)]}"> <group col="1" attrs="{'invisible': [('pad_freight_barcode', '=', False)]}">
<div> <div>
<separator string="刀盘:" style="font-size: 13px;"/> <separator string="刀盘:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="pad_code_id" placeholder="请选择" string="序列号" <field name="pad_freight_barcode" string="货位"/>
options="{'no_create': True, 'no_quick_create': True}"/> <field name="pad_product_id" string="名称"/>
<field name="pad_name" string="名称"/>
<field name="cutting_tool_cutterpad_model_id" string="型号"/> <field name="cutting_tool_cutterpad_model_id" string="型号"/>
<field name="pad_specification_id" string="规格"/> <field name="pad_specification_id" string="规格"/>
<field name="sf_tool_brand_id_4" string="品牌"/> <field name="sf_tool_brand_id_4" string="品牌"/>

View File

@@ -57,7 +57,7 @@
</group> </group>
</group> </group>
<notebook> <notebook>
<page string="序列号"> <page string="序列号" attrs="{'invisible': [('barcode_ids', '=', [])]}">
<field name="barcode_ids"> <field name="barcode_ids">
<tree> <tree>
<field name="name"/> <field name="name"/>

View File

@@ -9,7 +9,7 @@ class ToolChangeRequirementInformation(models.TransientModel):
_description = '换刀需求信息' _description = '换刀需求信息'
code = fields.Char('编码', readonly=True) 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) tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
name = fields.Char('名称', related='maintenance_equipment_id.name', store=True, 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) maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床', readonly=True)
@@ -221,114 +221,187 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
image = fields.Binary('图片') 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='整体式刀具序列号', integral_freight_barcode = fields.Char('整体式刀具货位')
domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'), integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
('tool_material_status', '=', '可用')]) compute='_compute_integral_product_id', store=True)
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
related='integral_code_id.product_id.cutting_tool_model_id') related='integral_product_id.cutting_tool_model_id')
integral_name = fields.Char('整体式刀具名称', related='integral_code_id.product_id.name')
integral_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='整体式刀具规格', 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='整体式刀具品牌', 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')
# 刀片型号 @api.depends('integral_freight_barcode')
blade_code_id = fields.Many2one('stock.lot', '刀片序列号', def _compute_integral_product_id(self):
domain=[('product_id.cutting_tool_material_id.name', '=', '刀片'), location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)])
('tool_material_status', '=', '可用')]) 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='刀片型号', cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
related='blade_code_id.product_id.cutting_tool_model_id') related='blade_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='刀片规格', blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格',
related='blade_code_id.product_id.specification_id') related='blade_product_id.specification_id')
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_code_id.product_id.brand_id') sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
# 刀杆型号 @api.depends('blade_freight_barcode')
bar_code_id = fields.Many2one('stock.lot', '刀杆序列号', def _compute_blade_product_id(self):
domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆'), location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)])
('tool_material_status', '=', '可用')]) 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='刀杆型号', cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
related='bar_code_id.product_id.cutting_tool_model_id') related='bar_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='刀杆规格', bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格',
related='bar_code_id.product_id.specification_id') related='bar_product_id.specification_id')
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_code_id.product_id.brand_id') sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
# 刀盘型号 @api.depends('bar_freight_barcode')
pad_code_id = fields.Many2one('stock.lot', '刀盘序列号', def _compute_bar_product_id(self):
domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘'), location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)])
('tool_material_status', '=', '可用')]) 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='刀盘型号', cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
related='pad_code_id.product_id.cutting_tool_model_id') related='pad_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='刀盘规格', pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格',
related='pad_code_id.product_id.specification_id') related='pad_product_id.specification_id')
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_code_id.product_id.brand_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, handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True,
domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'), domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'),
('tool_material_status', '=', '可用')]) ('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='刀柄型号', cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
related='handle_code_id.product_id.cutting_tool_model_id') 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='刀柄规格', handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格',
related='handle_code_id.product_id.specification_id') 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') sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_code_id.product_id.brand_id')
# 夹头型号 @api.depends('handle_code_id')
chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', required=True, def _compute_handle_product_id(self):
domain=[('product_id.cutting_tool_material_id.name', '=', '夹头'), if self.handle_code_id:
('tool_material_status', '=', '可用')]) 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='夹头型号', cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
related='chuck_code_id.product_id.cutting_tool_model_id') related='chuck_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='夹头规格', chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格',
related='chuck_code_id.product_id.specification_id') related='chuck_product_id.specification_id')
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_code_id.product_id.brand_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): def on_barcode_scanned(self, barcode):
""" """
智能工厂组装单处扫码绑定刀具物料') 智能工厂组装单处扫码绑定刀具物料
""" """
for record in self: for record in self:
if 'DJWL' in barcode: lot_ids = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
records = record.env['stock.lot'].search([('name', '=', barcode)]) if lot_ids:
if not records: for lot_id in lot_ids:
raise ValidationError('扫描的条形码数据不存在,请重新扫描!') if lot_id.quant_ids[-1].location_id.name in '刀具房':
for record_stock_lot in records: record.handle_code_id = lot_id.id
if record_stock_lot.quant_ids[-1].location_id.name == '刀具组装位置': elif lot_id.quant_ids[-1].location_id.name == '刀具组装位置':
raise ValidationError('该刀具物料已使用,请重新选择') raise ValidationError('该刀已使用,请重新扫描')
elif record_stock_lot.quant_ids[-1].location_id.name not in '刀具房': else:
raise ValidationError('该刀具物料未入库,请重新选择') raise ValidationError('该刀未入库,请重新扫描')
tool_material_name = record_stock_lot.product_id.cutting_tool_material_id.name else:
if tool_material_name == '整体式刀具': location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
record.integral_code_id = record_stock_lot.id if location:
elif tool_material_name == '刀片': material_name = location.product_id.cutting_tool_material_id.name
record.blade_code_id = record_stock_lot.id if material_name == '夹头':
elif tool_material_name == '刀杆': record.chuck_freight_barcode = barcode
record.bar_code_id = record_stock_lot.id elif material_name == '整体式刀具':
elif tool_material_name == '刀盘': record.integral_freight_barcode = barcode
record.pad_code_id = record_stock_lot.id record.blade_freight_barcode = ''
elif tool_material_name == '刀柄': record.bar_freight_barcode = ''
record.handle_code_id = record_stock_lot.id record.pad_freight_barcode = ''
elif tool_material_name == '夹头': elif material_name == '刀片':
record.chuck_code_id = record_stock_lot.id 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: else:
raise ValidationError('扫描的刀具物料不存在,请重新扫描!') raise ValidationError('扫描的刀具物料不存在,请重新扫描!')
else: else:
record.rfid = barcode 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:
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='功能刀具序列号') barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号')
rfid = fields.Char('rfid', required=True) rfid = fields.Char('Rfid', compute='_compute_rfid')
tool_code = fields.Char(string='功能刀具编码', readonly=True, compute='_compute_tool_code') tool_code = fields.Char(string='功能刀具编码', compute='_compute_tool_code')
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', compute='_compute_name') 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', after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model',
string='组装后功能刀具类型', string='组装后功能刀具类型')
compute='_compute_after_assembly_functional_tool_type_id')
after_assembly_functional_tool_diameter = fields.Integer(string='组装后功能刀具直径(mm)') after_assembly_functional_tool_diameter = fields.Integer(string='组装后功能刀具直径(mm)')
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)') after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)')
after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', default='0') 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)') after_assembly_effective_length = fields.Float(string='组装后有效长(mm)')
L_D_number = fields.Float(string='L/D值(mm)', compute='_compute_l_d_number') L_D_number = fields.Float(string='L/D值(mm)', compute='_compute_l_d_number')
hiding_length = fields.Float(string='避空长(mm)') 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) # functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
# res_partner_id = fields.Many2one('res.partner', '智能工厂', domain="[('is_factory', '=', True)]") # res_partner_id = fields.Many2one('res.partner', '智能工厂', domain="[('is_factory', '=', True)]")
@@ -357,30 +447,29 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
for obj in self: for obj in self:
str_1 = 'GNDJ-%s' % obj.after_assembly_functional_tool_type_id.code str_1 = 'GNDJ-%s' % obj.after_assembly_functional_tool_type_id.code
str_2 = '' str_2 = ''
num = None
if obj.handle_specification_id: if obj.handle_specification_id:
if obj.integral_specification_id: if obj.integral_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % ( str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.integral_specification_id.blade_diameter, obj.after_assembly_tool_loading_length, 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) obj.integral_specification_id.blade_length, obj.handle_specification_id.total_length)
num = self._get_code(str_2)
elif obj.bar_specification_id: elif obj.bar_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % ( str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.bar_specification_id.cutter_arbor_diameter, obj.after_assembly_tool_loading_length, 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) obj.bar_specification_id.blade_length, obj.handle_specification_id.total_length)
num = self._get_code(str_2)
elif obj.pad_specification_id: elif obj.pad_specification_id:
str_2 = '%s-D%sL%sB%sH%s-' % ( str_2 = '%s-D%sL%sB%sH%s-' % (
str_1, obj.pad_specification_id.cutter_head_diameter, obj.after_assembly_tool_loading_length, 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, 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: else:
obj.tool_code = None obj.tool_code = str_2
return True
obj.tool_code = str_2 + str(self._get_code(str_2))
else:
obj.tool_code = str_2
def _get_code(self, 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)], [('code', 'like', str_2)],
limit=1, limit=1,
order="id desc" order="id desc"
@@ -392,40 +481,30 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
num = "%03d" % m num = "%03d" % m
return num 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): def _compute_name(self):
for obj in self: for obj in self:
if obj.tool_groups_id: if obj.after_name_id:
obj.after_assembly_functional_tool_name = '%s-D%sR%s' % ( obj.after_assembly_functional_tool_name = obj.after_name_id.name
obj.tool_groups_id.name, obj.after_assembly_functional_tool_diameter,
obj.after_assembly_knife_tip_r_angle)
else: 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): def _onchange_after_assembly_functional_tool_diameter(self):
for obj in self: for obj in self:
if obj.integral_code_id: if obj.integral_product_id:
obj.after_assembly_functional_tool_diameter = obj.integral_code_id.product_id.cutting_tool_blade_diameter obj.after_assembly_functional_tool_diameter = obj.integral_product_id.cutting_tool_blade_diameter
else: else:
obj.after_assembly_functional_tool_diameter = 0 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): def _onchange_after_assembly_knife_tip_r_angle(self):
for obj in self: for obj in self:
if obj.blade_code_id: if obj.blade_product_id:
obj.after_assembly_knife_tip_r_angle = obj.blade_code_id.product_id.cutting_tool_blade_tip_circular_arc_radius obj.after_assembly_knife_tip_r_angle = obj.blade_product_id.cutting_tool_blade_tip_circular_arc_radius
else: else:
obj.after_assembly_knife_tip_r_angle = 0 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') @api.depends('hiding_length', 'after_assembly_functional_tool_diameter')
def _compute_l_d_number(self): def _compute_l_d_number(self):
for record in self: for record in self:
@@ -434,28 +513,23 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
else: else:
record.L_D_number = 0 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): def _check_length_control(self):
for obj in self: for obj in self:
if obj.after_assembly_tool_loading_length == 0: if obj.after_assembly_tool_loading_length == 0:
raise ValidationError('组装参数信息【总长度】不能为0') raise ValidationError('组装参数信息【总长度】不能为0')
if obj.after_assembly_functional_tool_length == 0: if obj.after_assembly_functional_tool_length == 0:
raise ValidationError('组装参数信息【伸出长】不能为0') raise ValidationError('组装参数信息【伸出长】不能为0')
if obj.after_assembly_max_lifetime_value == 0:
@api.constrains('rfid') raise ValidationError('组装参数信息【最大寿命值】不能为0')
def _check_rfid(self): if obj.after_assembly_alarm_value == 0:
self.get_rfid() raise ValidationError('组装参数信息【报警值】不能为0')
if obj.after_assembly_effective_length == 0:
@api.onchange('rfid') raise ValidationError('组装参数信息【有效长】不能为0')
def _onchange_rfid(self): if obj.hiding_length == 0:
self.get_rfid() raise ValidationError('组装参数信息【避空长】不能为0')
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)
def functional_tool_assembly(self): 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) 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: if self.handle_code_id:
product_id.tool_material_stock_moves(self.handle_code_id) product_id.tool_material_stock_moves(self.handle_code_id)
if self.chuck_code_id: if self.integral_product_id:
product_id.tool_material_stock_moves(self.chuck_code_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) 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({ 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, '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, 'diameter': self.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle, 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
'coarse_middle_thin': self.after_assembly_coarse_middle_thin, '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('【整体式刀具】和【刀片】必须填写一个!') raise ValidationError('【整体式刀具】和【刀片】必须填写一个!')
if self.blade_code_id: if self.blade_product_id:
if not self.bar_code_id and not self.pad_code_id: if not self.bar_product_id and not self.pad_product_id:
raise ValidationError('【刀盘】和【刀杆】必须填写一个!') raise ValidationError('【刀盘】和【刀杆】必须填写一个!')
def get_desc_1(self, stock_lot): def get_desc_1(self, stock_lot):
@@ -541,13 +615,13 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
'barcode_id': stock_lot.id, 'barcode_id': stock_lot.id,
'code': self.tool_code, 'code': self.tool_code,
'rfid': self.rfid, 'rfid': self.rfid,
'tool_groups_id': self.tool_groups_id.id, 'tool_groups_id': self.after_tool_groups_id.id,
'integral_code_id': self.integral_code_id.id, 'integral_freight_barcode': self.integral_freight_barcode,
'blade_code_id': self.blade_code_id.id, 'blade_freight_barcode': self.blade_freight_barcode,
'bar_code_id': self.bar_code_id.id, 'bar_freight_barcode': self.bar_freight_barcode,
'pad_code_id': self.pad_code_id.id, 'pad_freight_barcode': self.pad_freight_barcode,
'handle_code_id': self.handle_code_id.id, '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_name': self.after_assembly_functional_tool_name,
'after_assembly_functional_tool_type_id': self.after_assembly_functional_tool_type_id.id, 'after_assembly_functional_tool_type_id': self.after_assembly_functional_tool_type_id.id,
@@ -577,17 +651,18 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
return { return {
'barcode_id': stock_lot.id, 'barcode_id': stock_lot.id,
'code': self.tool_code, '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, '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, 'functional_tool_name_id': functional_tool_assembly_id.id,
'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_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_integral_model_id': self.integral_product_id.id,
'cutting_tool_blade_model_id': self.blade_code_id.product_id.id, 'cutting_tool_blade_model_id': self.blade_product_id.id,
'cutting_tool_cutterbar_model_id': self.bar_code_id.product_id.id, 'cutting_tool_cutterbar_model_id': self.bar_product_id.id,
'cutting_tool_cutterpad_model_id': self.pad_code_id.product_id.id, 'cutting_tool_cutterpad_model_id': self.pad_product_id.id,
'cutting_tool_cutterhandle_model_id': self.handle_code_id.product_id.id, 'cutting_tool_cutterhandle_model_id': self.handle_product_id.id,
'cutting_tool_cutterhead_model_id': self.chuck_code_id.product_id.id, 'cutting_tool_cutterhead_model_id': self.chuck_product_id.id,
'functional_tool_diameter': self.after_assembly_functional_tool_diameter, 'functional_tool_diameter': self.after_assembly_functional_tool_diameter,
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle, 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
@@ -641,7 +716,7 @@ class StockPicking(models.Model):
'code': obj.tool_code, 'code': obj.tool_code,
'rfid': obj.rfid, 'rfid': obj.rfid,
'functional_tool_name': obj.after_assembly_functional_tool_name, '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() 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) 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): class StockLot(models.Model):
_inherit = 'stock.lot' _inherit = 'stock.lot'
@@ -752,7 +853,7 @@ class StockLot(models.Model):
'code': '' if not obj else obj.tool_code, 'code': '' if not obj else obj.tool_code,
'rfid': '' if not obj else obj.rfid, 'rfid': '' if not obj else obj.rfid,
'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name, '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 return stock_move_id, stock_move_line_id

View File

@@ -200,97 +200,6 @@
</group> </group>
<group string="组装物料信息" col="1"> <group string="组装物料信息" col="1">
<field name="_barcode_scanned" widget="barcode_handler"/> <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"> <group col="1">
<div> <div>
<separator string="刀柄:" style="font-size: 13px;"/> <separator string="刀柄:" style="font-size: 13px;"/>
@@ -301,10 +210,13 @@
class="custom_required" class="custom_required"
options="{'no_create': True, 'no_quick_create': True}"/> options="{'no_create': True, 'no_quick_create': True}"/>
</group> </group>
<group>
<field name="handle_freight_rfid" string="Rfid"/>
</group>
</group> </group>
<group col="2"> <group col="2">
<group> <group>
<field name="handle_name" string="名称"/> <field name="handle_product_id" string="名称"/>
<field name="handle_specification_id" string="规格"/> <field name="handle_specification_id" string="规格"/>
</group> </group>
<group> <group>
@@ -313,20 +225,101 @@
</group> </group>
</group> </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"> <group col="1">
<div> <div>
<separator string="夹头:" style="font-size: 13px;"/> <separator string="夹头:" style="font-size: 13px;"/>
</div> </div>
<group> <group>
<group> <group>
<field name="chuck_code_id" string="序列号" placeholder="请选择" <field name="chuck_freight_barcode" string="货位"/>
class="custom_required"
options="{'no_create': True, 'no_quick_create': True}"/>
</group> </group>
</group> </group>
<group col="2"> <group col="2">
<group> <group>
<field name="chuck_name" string="名称"/> <field name="chuck_product_id" string="名称"/>
<field name="chuck_specification_id" string="规格"/> <field name="chuck_specification_id" string="规格"/>
</group> </group>
<group> <group>
@@ -338,23 +331,31 @@
</group> </group>
<group string="组装参数信息"> <group string="组装参数信息">
<group>
<group> <group>
<field name="barcode_id" invisible="True"/> <field name="barcode_id" invisible="True"/>
<field name="tool_code" readonly="True"/> <field name="tool_code" readonly="True"/>
<field name="rfid" placeholder="请输入rfid码" class="custom_required"/> <field name="rfid" class="custom_required"/>
<field name="after_assembly_functional_tool_name" string="功能刀具名称"/> <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="功能刀具类型" <field name="after_assembly_functional_tool_type_id" string="功能刀具类型"
options="{'no_create': True, 'no_quick_create': True}"/> options="{'no_create': True, 'no_quick_create': True}"/>
<field name="tool_groups_id"/> <field name="after_tool_groups_id"
options="{'no_create': True, 'no_quick_create': True}"/>
<field name="after_assembly_functional_tool_diameter" string="刀具直径(mm)" <field name="after_assembly_functional_tool_diameter" string="刀具直径(mm)"
class="custom_required"/> class="custom_required"/>
<field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)" <field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)"
class="custom_required"/> class="custom_required"/>
<field name="after_assembly_new_former" string="新/旧"/> <field name="after_assembly_new_former" string="新/旧"/>
<field name="cut_time" attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/> <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_length"
<field name="cut_number" attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/> attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
<field name="cut_number"
attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
</group> </group>
</group>
<group>
<group> <group>
<field name="after_assembly_whether_standard_knife" string="是否标准刀"/> <field name="after_assembly_whether_standard_knife" string="是否标准刀"/>
<field name="after_assembly_coarse_middle_thin" string="粗/中/精"/> <field name="after_assembly_coarse_middle_thin" string="粗/中/精"/>
@@ -366,11 +367,13 @@
class="custom_required"/> class="custom_required"/>
<field name="after_assembly_functional_tool_length" string="伸出长(mm)" <field name="after_assembly_functional_tool_length" string="伸出长(mm)"
class="custom_required"/> class="custom_required"/>
<field name="after_assembly_effective_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="hiding_length" class="custom_required"/>
<field name="L_D_number"/> <field name="L_D_number"/>
</group> </group>
</group> </group>
</group>
</sheet> </sheet>
<footer> <footer>
<button string="确定" name="functional_tool_assembly" type="object" class="btn-primary" <button string="确定" name="functional_tool_assembly" type="object" class="btn-primary"

View File

@@ -1,2 +1,3 @@
# -*-coding:utf-8-*- # -*-coding:utf-8-*-
from . import models from . import models
from . import wizard

View File

@@ -15,6 +15,7 @@
'data/ir_cron_data.xml', 'data/ir_cron_data.xml',
'security/sf_stock_security.xml', 'security/sf_stock_security.xml',
'security/ir.model.access.csv', 'security/ir.model.access.csv',
'wizard/wizard_view.xml',
'views/view.xml', 'views/view.xml',
'views/shelf_location.xml', 'views/shelf_location.xml',
'views/change_stock_move_views.xml', 'views/change_stock_move_views.xml',

View File

@@ -1,4 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re
import datetime import datetime
import logging import logging
import base64 import base64
@@ -19,14 +21,6 @@ class SfLocation(models.Model):
name = fields.Char('Location Name', required=True, size=20) name = fields.Char('Location Name', required=True, size=20)
barcode = fields.Char('Barcode', copy=False, size=15) 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库区、库位、货位 # 仓库类别selection库区、库位、货位
# location_type = fields.Selection([ # location_type = fields.Selection([
# ('库区', '库区'), # ('库区', '库区'),
@@ -132,7 +126,7 @@ class SfLocation(models.Model):
for record in self: for record in self:
if record.product_sn_id: if record.product_sn_id:
record.product_id = record.product_sn_id.product_id record.product_id = record.product_sn_id.product_id
record.location_status = '占用' # record.location_status = '占用'
else: else:
record.product_id = False record.product_id = False
# record.location_status = '空闲' # record.location_status = '空闲'
@@ -197,6 +191,7 @@ class SfLocation(models.Model):
# return res # return res
# 生成货位 # 生成货位
def create_location(self): def create_location(self):
""" """
当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量 当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量
@@ -228,11 +223,14 @@ class SfLocation(models.Model):
class SfShelf(models.Model): class SfShelf(models.Model):
_name = 'sf.shelf' _name = 'sf.shelf'
_inherit = ['printing.utils']
_description = '货架' _description = '货架'
_order = 'name' _order = 'create_date desc'
name = fields.Char('货架名称', required=True, size=20) name = fields.Char('货架名称', required=True, size=20)
active = fields.Boolean("有效", default=True)
barcode = fields.Char('编码', copy=False, size=15, required=True) barcode = fields.Char('编码', copy=False, size=15, required=True)
# 货位 # 货位
location_ids = fields.One2many('sf.shelf.location', 'shelf_id', string='货位') 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 j_str = str(j + 1).zfill(3) # 确保是两位数如果不足两位左侧补0
return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + i_str + '-' + j_str 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): class ShelfLocation(models.Model):
_name = 'sf.shelf.location' _name = 'sf.shelf.location'
_inherit = ['printing.utils']
_description = '货位' _description = '货位'
_order = 'name, id' _rec_name = 'barcode'
_order = 'id asc, create_date asc'
# current_location_id = fields.Many2one('sf.shelf.location', string='当前位置') # 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', '目标位置调拨单') destination_move_ids = fields.One2many('stock.move.line', 'destination_location_id', '目标位置调拨单')
storage_time = fields.Datetime('入库时间', compute='_compute_location_status') storage_time = fields.Datetime('入库时间', compute='_compute_location_status')
production_id = fields.Many2one('mrp.production', string='制造订单') production_id = fields.Many2one('mrp.production', string='制造订单')
active = fields.Boolean("有效", default=True)
@api.depends('location_status') @api.depends('location_status')
def _compute_location_status(self): def _compute_location_status(self):
@@ -332,6 +361,8 @@ class ShelfLocation(models.Model):
name = fields.Char('货位名称', required=True, size=20) name = fields.Char('货位名称', required=True, size=20)
barcode = fields.Char('货位编码', copy=False, size=50) 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='货架') shelf_id = fields.Many2one('sf.shelf', string='货架')
@@ -343,6 +374,62 @@ class ShelfLocation(models.Model):
def action_check(self): def action_check(self):
self.check_state = 'enable' 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库区、库位、货位 # # 仓库类别selection库区、库位、货位
# location_type = fields.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.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_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): def action_location_status_disable(self):
@@ -381,12 +478,20 @@ class ShelfLocation(models.Model):
""" """
for record in self: for record in self:
if record.product_sn_id: if record.product_sn_id:
try:
record.sudo().product_id = record.product_sn_id.product_id record.sudo().product_id = record.product_sn_id.product_id
record.sudo().location_status = '占用' # record.sudo().location_status = '占用'
record.sudo().product_num = 1
except Exception as e:
print('eeeeeee占用', e)
else: else:
record.product_id = False try:
# record.location_status = '空闲' 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): def get_sf_shelf_location_info(self):
@@ -411,6 +516,19 @@ class ShelfLocation(models.Model):
else: else:
raise UserError("该库位无产品") 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): class Sf_stock_move_line(models.Model):
_name = 'stock.move.line' _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) 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)
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): def action_revert_inventory(self):
# 检查用户是否有执行操作的权限 # 检查用户是否有执行操作的权限
@@ -430,7 +558,7 @@ class Sf_stock_move_line(models.Model):
raise UserError(_('抱歉,只有库管人员可以执行此动作')) raise UserError(_('抱歉,只有库管人员可以执行此动作'))
# 如果用户有权限,调用父类方法 # 如果用户有权限,调用父类方法
return super(CustomStockMoveLine, self).action_revert_inventory() return super().action_revert_inventory()
@api.depends('lot_name') @api.depends('lot_name')
def _compute_lot_qr_code(self): def _compute_lot_qr_code(self):
@@ -475,7 +603,7 @@ class Sf_stock_move_line(models.Model):
# port = 9100 # 可以根据实际情况修改 # 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: if not printer_config:
raise UserError('请先配置打印机') raise UserError('请先配置打印机')
host = printer_config.printer_id.ip_address 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): def _compute_location_dest_id_value(self):
for record in self: for record in self:
record.location_dest_id_value = record.location_dest_id.id if record.location_dest_id else False 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( destination_location_id = fields.Many2one(
'sf.shelf.location', string='目标货位') '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: for record in self:
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( shelf_location_obj = self.env['sf.shelf.location'].search(
[('product_sn_id', '=', record.lot_id.id)]) [('product_sn_id', '=', record.lot_id.id)])
if shelf_location_obj: if shelf_location_obj:
shelf_location_obj.product_sn_id = False 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: if obj:
obj.product_sn_id = record.lot_id.id obj.product_sn_id = record.lot_id.id
else: else:
pass
else:
obj = self.env['sf.shelf.location'].search([('name', '=',
self.destination_location_id.name)])
if obj: if obj:
obj.product_sn_id = record.lot_id.id obj.product_sn_id = record.lot_id.id
else:
if obj:
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): class SfStockPicking(models.Model):
@@ -739,11 +880,26 @@ class SfStockPicking(models.Model):
res = super(SfStockPicking, self).button_validate() res = super(SfStockPicking, self).button_validate()
for line in self.move_line_ids: for line in self.move_line_ids:
if line: if line:
# 调用入库方法进行入库
line.compute_destination_location_id()
if line.current_location_id: if line.current_location_id:
if line.current_location_id.product_sn_id:
line.current_location_id.product_sn_id = False line.current_location_id.product_sn_id = False
line.current_location_id.location_status = '空闲' # 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 return res
# def print_all_barcode(self): # def print_all_barcode(self):
# """ # """
# 打印所有编码 # 打印所有编码
@@ -822,117 +978,55 @@ class SfProcurementGroup(models.Model):
return res return res
class SfWarehouse(models.Model): # class SfPickingType(models.Model):
_inherit = 'stock.warehouse' # _inherit = 'stock.picking.type'
#
check_state = fields.Selection([ # def _default_show_operations(self):
('enable', '启用'), # return self.user_has_groups('stock.group_production_lot,'
('close', '关闭') # 'stock.group_stock_multi_locations,'
], string='审核状态', default='close') # 'stock.group_tracking_lot',
# 'sf_warehouse.group_sf_stock_user',
def action_check(self): # 'sf_warehouse.group_sf_stock_manager')
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): class SfPickingType(models.Model):
_inherit = 'stock.picking.type' _inherit = 'stock.picking.type'
check_state = fields.Selection([ def _default_show_operations(self):
('enable', '启用'), return self.user_has_groups(
('close', '关闭') 'stock.group_production_lot,'
], string='审核状态', default='close') 'stock.group_stock_multi_locations,'
'stock.group_tracking_lot,'
def action_check(self): 'sf_warehouse.group_sf_stock_user,'
self.check_state = 'enable' 'sf_warehouse.group_sf_stock_manager'
)
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'
class CustomStockMove(models.Model): class CustomStockMove(models.Model):
_name = 'stock.move' _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): def action_assign_serial_show_details(self):
# 首先执行原有逻辑 # 首先执行原有逻辑
@@ -983,7 +1077,7 @@ class CustomStockMove(models.Model):
# port = 9100 # 可以根据实际情况修改 # 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: if not printer_config:
raise UserError('请先配置打印机') raise UserError('请先配置打印机')
host = printer_config.printer_id.ip_address host = printer_config.printer_id.ip_address

View File

@@ -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_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_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_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_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_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_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_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 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_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_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
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
104 access_stock_lot_group_plan_dispatch stock.lot stock.model_stock_lot sf_base.group_plan_dispatch 1 0 0 0
105 access_stock_lot_group_plan_director stock.lot stock.model_stock_lot sf_base.group_plan_director 1 1 1 0
106 access_stock_warehouse_orderpoint stock.warehouse.orderpoint stock.model_stock_warehouse_orderpoint sf_base.group_plan_dispatch 1 1 0 0
107 access_product_product access_stock_inventory_conflict product.product stock.inventory.conflict product.model_product_product stock.model_stock_inventory_conflict sf_base.group_plan_dispatch 1 0 0 0
108 access_product_template access_stock_inventory_warning product.template stock.inventory.warning product.model_product_template stock.model_stock_inventory_warning sf_base.group_plan_dispatch 1 0 0 0
109 access_product_product access_stock_inventory_adjustment_name product.product stock.inventory.adjustment.name product.model_product_product stock.model_stock_inventory_adjustment_name sf_base.group_plan_director sf_base.group_plan_dispatch 1 1 0 1 0 0
110 access_product_template access_mrp_production_group_purchase product.template mrp_production_group_purchase product.model_product_template mrp.model_mrp_production sf_base.group_plan_director sf_base.group_purchase 1 1 0 1 0 0
111 access_stock_inventory_conflict access_mrp_production_group_purchase_director stock.inventory.conflict mrp_production_group_purchase_director stock.model_stock_inventory_conflict mrp.model_mrp_production sf_base.group_plan_dispatch sf_base.group_purchase_director 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
access_mrp_production_group_purchase mrp_production_group_purchase mrp.model_mrp_production sf_base.group_purchase 1 0 0 0
access_mrp_production_group_purchase_director mrp_production_group_purchase_director mrp.model_mrp_production sf_base.group_purchase_director 1 0 0 0
access_mrp_workorder_group_purchase mrp_workorder_group_purchase mrp.model_mrp_workorder sf_base.group_purchase 1 0 0 0
access_mrp_workorder_group_purchase_director mrp_workorder_group_purchase_director mrp.model_mrp_workorder sf_base.group_purchase_director 1 0 0 0
112 access_mrp_unbuild_group_purchase access_mrp_workorder_group_purchase mrp_unbuild_group_purchase mrp_workorder_group_purchase mrp.model_mrp_unbuild mrp.model_mrp_workorder sf_base.group_purchase 1 0 0 0
113 access_mrp_unbuild_group_purchase_director access_mrp_workorder_group_purchase_director mrp_unbuild_group_purchase_director mrp_workorder_group_purchase_director mrp.model_mrp_unbuild mrp.model_mrp_workorder sf_base.group_purchase_director 1 0 0 0
114 access_stock_scrap_group_purchase access_mrp_unbuild_group_purchase stock_scrap_group_purchase mrp_unbuild_group_purchase stock.model_stock_scrap mrp.model_mrp_unbuild sf_base.group_purchase 1 0 0 0
134
135
136
137
138
139
140
141
142

View File

@@ -10,10 +10,18 @@
<field name="current_location_id" force_save="1"/> <field name="current_location_id" force_save="1"/>
</xpath> </xpath>
<xpath expr="//field[@name='location_dest_id'][2]" position="after"> <xpath expr="//field[@name='location_dest_id'][2]" position="after">
<field name="destination_location_id" domain="[ <field name="current_product_id" invisible="1"/>
('location_id', '=', location_dest_id_value), <field name="there_is_no_sn" invisible="1"/>
('location_status', '=', '空闲') <!-- <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_product_type"/> -->
<!-- <field name="location_dest_id"/> --> <!-- <field name="location_dest_id"/> -->
<field name="location_dest_id_value" invisible="1"/> <field name="location_dest_id_value" invisible="1"/>
@@ -40,6 +48,7 @@
</field> </field>
</record> </record>
<record id="sf_stock_move_line_form" model="ir.ui.view"> <record id="sf_stock_move_line_form" model="ir.ui.view">
<field name="name">sf.stock.move.line.form</field> <field name="name">sf.stock.move.line.form</field>
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
@@ -63,6 +72,9 @@
<field name="model">stock.move.line</field> <field name="model">stock.move.line</field>
<field name="inherit_id" ref="stock.view_stock_move_line_operation_tree"/> <field name="inherit_id" ref="stock.view_stock_move_line_operation_tree"/>
<field name="arch" type="xml"> <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"> <xpath expr="//field[@name='product_uom_id']" position="after">
<field name="lot_qr_code" widget="image"/> <field name="lot_qr_code" widget="image"/>
<button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/> <button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/>
@@ -117,7 +129,7 @@
<field name="inherit_id" ref="stock.stock_scrap_form_view"/> <field name="inherit_id" ref="stock.stock_scrap_form_view"/>
<field name="arch" type="xml"> <field name="arch" type="xml">
<xpath expr="//header//button[@name='action_validate']" position="replace"> <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" context="{'not_unlink_on_discard': True}" data-hotkey="v"
groups="sf_warehouse.group_sf_stock_user"/> groups="sf_warehouse.group_sf_stock_user"/>
</xpath> </xpath>
@@ -149,7 +161,19 @@
<!-- <button name="print_all_barcode" type="object" string="打印所有编码"/> --> <!-- <button name="print_all_barcode" type="object" string="打印所有编码"/> -->
<!-- </xpath> --> <!-- </xpath> -->
<xpath expr="//form//field[@name='product_id']" position="before"> <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> </xpath>
</field> </field>
</record> </record>

View File

@@ -9,7 +9,8 @@
<form string="Sf Shelf"> <form string="Sf Shelf">
<header> <header>
<field name="is_there_area" invisible="1"/> <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> </header>
<sheet> <sheet>
<group> <group>
@@ -23,12 +24,21 @@
<field name="shelf_layer" string="货架层数"/> <field name="shelf_layer" string="货架层数"/>
<field name="layer_capacity" string="层数容量"/> <field name="layer_capacity" string="层数容量"/>
</group> </group>
<notebook>
<page string="货位">
<button name="print_all_location_barcode" type="object" string="一键打印"
class="oe_highlight"/>
<field name="location_ids" widget="one2many_list"> <field name="location_ids" widget="one2many_list">
<tree string="Shelf Location"> <tree string="Shelf Location">
<field name="barcode" string="编码"/> <field name="barcode" string="编码"/>
<field name="name" 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> </tree>
</field> </field>
</page>
</notebook>
</sheet> </sheet>
</form> </form>
</field> </field>
@@ -116,13 +126,25 @@
<field name="name">Shelf Location form</field> <field name="name">Shelf Location form</field>
<field name="model">sf.shelf.location</field> <field name="model">sf.shelf.location</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<form string="Shelf Location"> <form string="Shelf Location" create="0">
<header> <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"/> <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', '!=', '空闲')]}"/> 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', '!=', '禁用')]}"/> attrs="{'invisible': [('location_status', '!=', '禁用')]}"/>
</header> </header>
<sheet> <sheet>
@@ -143,12 +165,13 @@
</button> </button>
</div> </div>
<group> <group>
<field name="barcode"/> <field name="barcode" readonly="1"/>
<field name="name"/> <field name="name" readonly="1"/>
<field name="shelf_id"/> <field name="shelf_id" readonly="1"/>
<field name="location_id"/> <field name="location_id" readonly="1"/>
<field name="product_sn_id"/> <field name="product_sn_id" options="{'no_create': True}"/>
<field name="product_id"/> <field name="product_id"/>
<field name="product_num" readonly="1"/>
<field name="location_status"/> <field name="location_status"/>
<field name="storage_time" widget="datetime"/> <field name="storage_time" widget="datetime"/>
<field name="production_id" readonly="1"/> <field name="production_id" readonly="1"/>
@@ -162,7 +185,7 @@
<field name="name">shelf.location.kanban</field> <field name="name">shelf.location.kanban</field>
<field name="model">sf.shelf.location</field> <field name="model">sf.shelf.location</field>
<field name="arch" type="xml"> <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> <templates>
<t t-name="kanban-box"> <t t-name="kanban-box">
<div t-attf-class="oe_kanban_card oe_kanban_global_click <div t-attf-class="oe_kanban_card oe_kanban_global_click
@@ -222,6 +245,7 @@
<field name="model">sf.shelf.location</field> <field name="model">sf.shelf.location</field>
<field name="arch" type="xml"> <field name="arch" type="xml">
<search string="货位"> <search string="货位">
<field name="barcode"/>
<searchpanel class="account_root"> <searchpanel class="account_root">
<!-- <field name="location_type" icon="fa-filter"/> --> <!-- <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"/> -->

View File

@@ -67,16 +67,16 @@
</notebook> </notebook>
</xpath> </xpath>
<xpath expr="//sheet" position="before"> <!-- <xpath expr="//sheet" position="before">-->
<header> <!-- <header>-->
<field name="check_state" invisible="1"/> <!-- <field name="check_state" invisible="1"/>-->
<button name="action_check" string="审核" type="object" <!-- <button name="action_check" string="审核" type="object"-->
attrs="{'invisible': [('check_state','=', 'enable')]}" <!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
groups="sf_warehouse.group_sf_stock_manager" <!-- groups="sf_warehouse.group_sf_stock_manager"-->
class="oe_highlight"/> <!-- class="oe_highlight"/>-->
</header> <!-- </header>-->
</xpath> <!-- </xpath>-->
</field> </field>
</record> </record>
@@ -188,23 +188,23 @@
<!-- </record>--> <!-- </record>-->
<!--仓库根据权限增加审核按钮--> <!--仓库根据权限增加审核按钮-->
<record id="view_warehouse_form_sf_inherit" model="ir.ui.view"> <!-- <record id="view_warehouse_form_sf_inherit" model="ir.ui.view">-->
<field name="name">stock.warehouse.form.sf.inherit</field> <!-- <field name="name">stock.warehouse.form.sf.inherit</field>-->
<field name="model">stock.warehouse</field> <!-- <field name="model">stock.warehouse</field>-->
<field name="inherit_id" ref="stock.view_warehouse"/> <!-- <field name="inherit_id" ref="stock.view_warehouse"/>-->
<field name="arch" type="xml"> <!-- <field name="arch" type="xml">-->
<xpath expr="//sheet" position="before"> <!-- <xpath expr="//sheet" position="before">-->
<header> <!-- <header>-->
<field name="check_state" invisible="1"/> <!-- <field name="check_state" invisible="1"/>-->
<button name="action_check" string="审核" type="object" <!-- <button name="action_check" string="审核" type="object"-->
attrs="{'invisible': [('check_state','=', 'enable')]}" <!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
groups="sf_warehouse.group_sf_stock_manager" <!-- groups="sf_warehouse.group_sf_stock_manager"-->
class="oe_highlight"/> <!-- class="oe_highlight"/>-->
</header> <!-- </header>-->
</xpath> <!-- </xpath>-->
</field> <!-- </field>-->
</record> <!-- </record>-->
<!-- <record id="view_warehouse_tree_sf_inherit" model="ir.ui.view">--> <!-- <record id="view_warehouse_tree_sf_inherit" model="ir.ui.view">-->
<!-- <field name="name">stock.warehouse.tree.sf.inherit</field>--> <!-- <field name="name">stock.warehouse.tree.sf.inherit</field>-->
@@ -220,23 +220,23 @@
<!--路线根据权限增加审核按钮--> <!--路线根据权限增加审核按钮-->
<record id="view_route_form_sf_inherit" model="ir.ui.view"> <!-- <record id="view_route_form_sf_inherit" model="ir.ui.view">-->
<field name="name">stock.route.form.sf.inherit</field> <!-- <field name="name">stock.route.form.sf.inherit</field>-->
<field name="model">stock.route</field> <!-- <field name="model">stock.route</field>-->
<field name="inherit_id" ref="stock.stock_location_route_form_view"/> <!-- <field name="inherit_id" ref="stock.stock_location_route_form_view"/>-->
<field name="arch" type="xml"> <!-- <field name="arch" type="xml">-->
<xpath expr="//sheet" position="before"> <!-- <xpath expr="//sheet" position="before">-->
<header> <!-- <header>-->
<field name="check_state" invisible="1"/> <!-- <field name="check_state" invisible="1"/>-->
<button name="action_check" string="审核" type="object" <!-- <button name="action_check" string="审核" type="object"-->
attrs="{'invisible': [('check_state','=', 'enable')]}" <!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
groups="sf_warehouse.group_sf_stock_manager" <!-- groups="sf_warehouse.group_sf_stock_manager"-->
class="oe_highlight"/> <!-- class="oe_highlight"/>-->
</header> <!-- </header>-->
</xpath> <!-- </xpath>-->
</field> <!-- </field>-->
</record> <!-- </record>-->
<!-- <record id="view_route_tree_sf_inherit" model="ir.ui.view">--> <!-- <record id="view_route_tree_sf_inherit" model="ir.ui.view">-->
<!-- <field name="name">stock.route.tree.sf.inherit</field>--> <!-- <field name="name">stock.route.tree.sf.inherit</field>-->
@@ -251,23 +251,23 @@
<!-- </record>--> <!-- </record>-->
<!--规则根据权限增加审核按钮--> <!--规则根据权限增加审核按钮-->
<record id="view_rule_form_sf_inherit" model="ir.ui.view"> <!-- <record id="view_rule_form_sf_inherit" model="ir.ui.view">-->
<field name="name">stock.rule.form.sf.inherit</field> <!-- <field name="name">stock.rule.form.sf.inherit</field>-->
<field name="model">stock.rule</field> <!-- <field name="model">stock.rule</field>-->
<field name="inherit_id" ref="stock.view_stock_rule_form"/> <!-- <field name="inherit_id" ref="stock.view_stock_rule_form"/>-->
<field name="arch" type="xml"> <!-- <field name="arch" type="xml">-->
<xpath expr="//sheet" position="before"> <!-- <xpath expr="//sheet" position="before">-->
<header> <!-- <header>-->
<field name="check_state" invisible="1"/> <!-- <field name="check_state" invisible="1"/>-->
<button name="action_check" string="审核" type="object" <!-- <button name="action_check" string="审核" type="object"-->
attrs="{'invisible': [('check_state','=', 'enable')]}" <!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
groups="sf_warehouse.group_sf_stock_manager" <!-- groups="sf_warehouse.group_sf_stock_manager"-->
class="oe_highlight"/> <!-- class="oe_highlight"/>-->
</header> <!-- </header>-->
</xpath> <!-- </xpath>-->
</field> <!-- </field>-->
</record> <!-- </record>-->
<!-- <record id="view_rule_tree_sf_inherit" model="ir.ui.view">--> <!-- <record id="view_rule_tree_sf_inherit" model="ir.ui.view">-->
<!-- <field name="name">stock.rule.tree.sf.inherit</field>--> <!-- <field name="name">stock.rule.tree.sf.inherit</field>-->
@@ -282,23 +282,23 @@
<!-- </record>--> <!-- </record>-->
<!--作业类型根据权限增加审核按钮--> <!--作业类型根据权限增加审核按钮-->
<record id="view_picking_type_form_sf_inherit" model="ir.ui.view"> <!-- <record id="view_picking_type_form_sf_inherit" model="ir.ui.view">-->
<field name="name">stock.picking.type.form.sf.inherit</field> <!-- <field name="name">stock.picking.type.form.sf.inherit</field>-->
<field name="model">stock.picking.type</field> <!-- <field name="model">stock.picking.type</field>-->
<field name="inherit_id" ref="stock.view_picking_type_form"/> <!-- <field name="inherit_id" ref="stock.view_picking_type_form"/>-->
<field name="arch" type="xml"> <!-- <field name="arch" type="xml">-->
<xpath expr="//sheet" position="before"> <!-- <xpath expr="//sheet" position="before">-->
<header> <!-- <header>-->
<field name="check_state" invisible="1"/> <!-- <field name="check_state" invisible="1"/>-->
<button name="action_check" string="审核" type="object" <!-- <button name="action_check" string="审核" type="object"-->
attrs="{'invisible': [('check_state','=', 'enable')]}" <!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
groups="sf_warehouse.group_sf_stock_manager" <!-- groups="sf_warehouse.group_sf_stock_manager"-->
class="oe_highlight"/> <!-- class="oe_highlight"/>-->
</header> <!-- </header>-->
</xpath> <!-- </xpath>-->
</field> <!-- </field>-->
</record> <!-- </record>-->
<!-- <record id="view_picking_type_tree_sf_inherit" model="ir.ui.view">--> <!-- <record id="view_picking_type_tree_sf_inherit" model="ir.ui.view">-->
<!-- <field name="name">stock.picking.type.tree.sf.inherit</field>--> <!-- <field name="name">stock.picking.type.tree.sf.inherit</field>-->

View File

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

View 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'}

View 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>