From 07ed60e8a793464f25ce940fd6aa0c57336a7830 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Mon, 19 Feb 2024 14:35:51 +0800 Subject: [PATCH 01/17] =?UTF-8?q?=E5=88=80=E5=85=B7=E7=AE=A1=E7=90=86?= =?UTF-8?q?=E6=9D=83=E9=99=90=E4=BC=98=E5=8C=96?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../security/ir.model.access.csv | 20 +++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/sf_tool_management/security/ir.model.access.csv b/sf_tool_management/security/ir.model.access.csv index 9dc6faeb..91eebb6f 100644 --- a/sf_tool_management/security/ir.model.access.csv +++ b/sf_tool_management/security/ir.model.access.csv @@ -1,18 +1,18 @@ 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,1 -access_sf_functional_tool_warning,sf.functional.tool.warning,model_sf_functional_tool_warning,sf_base.group_sf_tool_user,1,1,1,1 -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,1 +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,1 -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,1 +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,1 -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,1 +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,1 -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,1 -access_sf_tool_material_search,sf.tool.material.search,model_sf_tool_material_search,sf_base.group_sf_tool_user,1,1,1,1 +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_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 From 9c080e0cb4651a9ceb06b778ab60d0efde0fa264 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Mon, 19 Feb 2024 15:26:36 +0800 Subject: [PATCH 02/17] =?UTF-8?q?=E6=9D=83=E9=99=90=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=A2=9E=E8=A1=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/security/ir.model.access.csv | 6 ++++++ sf_plan/security/ir.model.access.csv | 2 +- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 188e0e64..35fb61d9 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -177,3 +177,9 @@ access_sf_fixture_materials_basic_parameters,sf_fixture_materials_basic_paramete access_mrp_production_group_sale_salemanager,mrp_production_group_sale_salemanager,mrp.model_mrp_production,sf_base.group_sale_salemanager,1,0,0,0 access_mrp_production_group_sale_director,mrp_production_group_sale_director,mrp.model_mrp_production,sf_base.group_sale_director,1,0,0,0 + +access_material_apply_group_plan_dispatch,material_apply,model_material_apply,sf_base.group_plan_dispatch,1,0,0,0 +access_sf_machine_brand_tags_group_plan_dispatch,sf_machine_brand_tags,model_sf_machine_brand_tags,sf_base.group_plan_dispatch,1,0,0,0 +access_ir_actions_act_window_group_plan_dispatch,ir.actions.act_window,base.model_ir_actions_act_window,sf_base.group_plan_dispatch,1,0,0,0 +access_ir_actions_act_window_view_group_plan_dispatch,ir.actions.act_window.view,base.model_ir_actions_act_window_view,sf_base.group_plan_dispatch,1,0,0,0 +access_sf_supplier_sort_group_plan_dispatch,sf.supplier.sort,model_sf_supplier_sort,sf_base.group_plan_dispatch,1,0,0,0 \ No newline at end of file diff --git a/sf_plan/security/ir.model.access.csv b/sf_plan/security/ir.model.access.csv index be1708f7..a17f2683 100644 --- a/sf_plan/security/ir.model.access.csv +++ b/sf_plan/security/ir.model.access.csv @@ -1,5 +1,5 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink access_sf_production_plan,sf.production.plan,model_sf_production_plan,base.group_user,1,0,0,0 -access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,1,0 +access_sf_production_plan_for_dispatch,sf.production.plan for dispatch,model_sf_production_plan,sf_base.group_plan_dispatch,1,1,0,0 access_sf_action_plan_all_wizard,sf.action.plan.all.wizard,model_sf_action_plan_all_wizard,base.group_user,1,1,1,1 \ No newline at end of file From cbd7b561de3c3b0bc39b846ecedca089958ce48d Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Mon, 19 Feb 2024 17:07:42 +0800 Subject: [PATCH 03/17] =?UTF-8?q?=E4=BA=A7=E5=93=81=E7=9A=84=E5=8A=A0?= =?UTF-8?q?=E5=B7=A5=E5=8F=82=E6=95=B0=E7=9A=84=E6=9D=83=E9=99=90=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/security/ir.model.access.csv | 3 +++ sf_manufacturing/security/ir.model.access.csv | 3 +++ 2 files changed, 6 insertions(+) diff --git a/sf_base/security/ir.model.access.csv b/sf_base/security/ir.model.access.csv index 188e0e64..372e199e 100644 --- a/sf_base/security/ir.model.access.csv +++ b/sf_base/security/ir.model.access.csv @@ -22,6 +22,9 @@ access_sf_processing_technology_admin,sf_processing_technology_admin,model_sf_pr access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,0 access_sf_supplier_sort_admin,sf_supplier_sort_admin,model_sf_supplier_sort,base.group_system,1,1,1,0 access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,0 +access_sf_production_process_parameter_group_plan_director,sf_production_process_parameter_group_plan_director,model_sf_production_process_parameter,sf_base.group_plan_director,1,0,0,0 +access_sf_production_process_parameter_group_purchase_director,sf_production_process_parameter_group_purchase_director,model_sf_production_process_parameter,sf_base.group_purchase_director,1,0,0,0 +access_sf_production_process_parameter_group_sale_director,sf_production_process_parameter_group_sale_director,model_sf_production_process_parameter,sf_base.group_sale_director,1,0,0,0 access_sf_production_process_parameter_admin,sf_production_process_parameter_admin,model_sf_production_process_parameter,base.group_system,1,1,1,0 access_sf_production_process_category,sf_production_process_category,model_sf_production_process_category,base.group_user,1,1,1,0 access_sf_production_process_category_admin,sf_production_process_category_admin,model_sf_production_process_category,base.group_system,1,1,1,0 diff --git a/sf_manufacturing/security/ir.model.access.csv b/sf_manufacturing/security/ir.model.access.csv index 345407ac..fb218c88 100644 --- a/sf_manufacturing/security/ir.model.access.csv +++ b/sf_manufacturing/security/ir.model.access.csv @@ -3,6 +3,9 @@ access_sf_cnc_processing,sf_cnc_processing,model_sf_cnc_processing,sf_base.group access_sf_cnc_processing_manager,sf_cnc_processing,model_sf_cnc_processing,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_model_type,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_model_type_manager,sf_model_type,model_sf_model_type,sf_base.group_sf_mrp_manager,1,1,1,0 +access_sf_model_type_group_sale_director,sf_model_type_group_sale_director,model_sf_model_type,sf_base.group_sale_director,1,0,0,0 +access_sf_model_type_group_purchase_director,sf_model_type_group_purchase_director,model_sf_model_type,sf_base.group_purchase_director,1,0,0,0 +access_sf_model_type_group_plan_director,sf_model_type_group_plan_director,model_sf_model_type,sf_base.group_plan_director,1,0,0,0 access_sf_product_model_type_routing_sort,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0 access_sf_product_model_type_routing_sort_manager,sf_product_model_type_routing_sort,model_sf_product_model_type_routing_sort,sf_base.group_sf_mrp_manager,1,1,1,0 access_sf_embryo_model_type_routing_sort,sf_embryo_model_type_routing_sort,model_sf_embryo_model_type_routing_sort,sf_base.group_sf_mrp_user,1,0,0,0 From 635583826fa4aba6b3831c3b1e49126570558d2f Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Mon, 19 Feb 2024 17:23:57 +0800 Subject: [PATCH 04/17] =?UTF-8?q?=E7=89=A9=E6=B5=81=E5=A4=84bug=E4=BF=AE?= =?UTF-8?q?=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_bf_connect/models/jd_eclp.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_bf_connect/models/jd_eclp.py b/sf_bf_connect/models/jd_eclp.py index 49337083..45fae2d8 100644 --- a/sf_bf_connect/models/jd_eclp.py +++ b/sf_bf_connect/models/jd_eclp.py @@ -57,7 +57,7 @@ class JdEclp(models.Model): res = super(JdEclp, self).button_validate() if self.check_out == 'OUT': if self.logistics_way != '自提': - if self.logistics_status != '3': + if self.logistics_status != '2': raise ValidationError('非自提订单,必须先下物流单,并获取物流面单后才可出库!') return res From efdde5aef0e37205b1515650ea00c8737eff634d Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 20 Feb 2024 13:09:25 +0800 Subject: [PATCH 05/17] =?UTF-8?q?=E5=88=86=E9=85=8D=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8F=B7=E6=97=B6=E5=A2=9E=E5=8A=A0=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E7=94=9F=E6=88=90=E5=8F=8A=E7=BC=96=E7=A0=81=E6=89=93=E5=8D=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/models/model.py | 143 +++++++++++++++++- .../views/change_stock_move_views.xml | 16 ++ 2 files changed, 158 insertions(+), 1 deletion(-) diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index 26b336d1..02c52392 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -1,6 +1,9 @@ # -*- coding: utf-8 -*- import datetime import logging +import base64 +import qrcode +import io from odoo import api, fields, models, _ from odoo.osv import expression from odoo.exceptions import UserError @@ -230,7 +233,7 @@ class ShelfLocation(models.Model): # destination_location_id = fields.Many2one('sf.shelf.location', string='目的位置') current_move_ids = fields.One2many('stock.move.line', 'current_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') @api.depends('location_status') def _compute_location_status(self): @@ -375,6 +378,112 @@ class Sf_stock_move_line(models.Model): # location_dest_id = fields.Many2one('stock.location', string='目标库位') location_dest_id_product_type = fields.Many2many(related='location_dest_id.product_type') 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) + + @api.depends('lot_name') + def _compute_lot_qr_code(self): + for record in self: + if record.lot_id: + # record.lot_qr_code = record.lot_id.lot_qr_code + # 创建一个QRCode对象 + qr = qrcode.QRCode( + version=1, # 设置版本, 1-40,控制二维码的大小 + error_correction=qrcode.constants.ERROR_CORRECT_L, # 设置错误校正等级 + box_size=10, # 设置每个格子的像素大小 + border=4, # 设置边框的格子宽度 + ) + + # 添加数据 + qr.add_data(self.lot_id.name) + 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.lot_qr_code = data + else: + record.lot_qr_code = False + + def print_qr_code(self): + self.ensure_one() # 确保这个方法只为一个记录调用 + # if not self.lot_id: + # raise UserError("没有找到序列号。") + # 假设_lot_qr_code方法已经生成了二维码并保存在字段中 + qr_code_data = self.lot_qr_code + if not qr_code_data: + raise UserError("没有找到二维码数据。") + + # 生成下载链接或直接触发下载 + # 此处的实现依赖于你的具体需求,以下是触发下载的一种示例 + attachment = self.env['ir.attachment'].sudo().create({ + 'datas': self.lot_qr_code, + 'type': 'binary', + 'description': '二维码图片', + 'name': self.lot_name + '.png', + # 'res_id': invoice.id, + # 'res_model': 'stock.picking', + 'public': True, + 'mimetype': 'application/x-png', + # 'model_name': 'stock.picking', + }) + # 返回附件的下载链接 + download_url = '/web/content/%s?download=true' % attachment.id + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + return { + 'type': 'ir.actions.act_url', + 'url': str(base_url) + download_url, + 'target': 'self', + } + + # # # 定义一个方法,用于根据序列号生成二维码 + # # @api.depends('lot_id') + # def generate_lot_qr_code(self): + # # 创建一个QRCode对象 + # qr = qrcode.QRCode( + # version=1, # 设置版本, 1-40,控制二维码的大小 + # error_correction=qrcode.constants.ERROR_CORRECT_L, # 设置错误校正等级 + # box_size=10, # 设置每个格子的像素大小 + # border=4, # 设置边框的格子宽度 + # ) + # + # # 添加数据 + # qr.add_data(self.lot_id.name) + # 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.lot_qr_code = data + # attachment = self.env['ir.attachment'].sudo().create({ + # 'datas': data, + # 'type': 'binary', + # 'description': '二维码图片', + # 'name': self.lot_id.name + '.png', + # # 'res_id': invoice.id, + # # 'res_model': 'stock.picking', + # 'public': True, + # 'mimetype': 'application/pdf', + # # 'model_name': 'stock.picking', + # }) # def button_test(self): # print(self.picking_id.name) @@ -652,3 +761,35 @@ class SfStockScrap(models.Model): def action_check(self): self.check_state = 'enable' + + +class CustomStockMove(models.Model): + _inherit = 'stock.move' + + def action_assign_serial_show_details(self): + # 首先执行原有逻辑 + result = super(CustomStockMove, self).action_assign_serial_show_details() + # 接着为每个 lot_name 生成二维码 + move_lines = self.move_line_ids # 获取当前 stock.move 对应的所有 stock.move.line 记录 + for line in move_lines: + if line.lot_name: # 确保 lot_name 存在 + qr_data = self.compute_lot_qr_code(line.lot_name) + # 假设 stock.move.line 模型中有一个字段叫做 lot_qr_code 用于存储二维码数据 + line.lot_qr_code = qr_data + return result + + def compute_lot_qr_code(self, lot_name): + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=4, + ) + qr.add_data(lot_name) + 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() + data = base64.b64encode(binary_data).decode() # 确保返回的是字符串形式的数据 + return data diff --git a/sf_warehouse/views/change_stock_move_views.xml b/sf_warehouse/views/change_stock_move_views.xml index b10eaaa9..40294a20 100644 --- a/sf_warehouse/views/change_stock_move_views.xml +++ b/sf_warehouse/views/change_stock_move_views.xml @@ -51,6 +51,22 @@ + + + + + + + + + + sf.stock.move.line.operation.tree + stock.move.line + + + + + - From cf3ec1b6ae84923756ed899fc5b9c4d2a00035d4 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Tue, 20 Feb 2024 15:59:58 +0800 Subject: [PATCH 10/17] =?UTF-8?q?1=E3=80=81=E5=BA=8F=E5=88=97=E5=8F=B7?= =?UTF-8?q?=E6=A8=A1=E5=9E=8B=E6=B7=BB=E5=8A=A0=E4=BA=8C=E7=BB=B4=E7=A0=81?= =?UTF-8?q?=E5=AD=97=E6=AE=B5=EF=BC=8C=E6=B7=BB=E5=8A=A0=E8=87=AA=E5=8A=A8?= =?UTF-8?q?=E6=A0=B9=E6=8D=AE=E5=BA=8F=E5=88=97=E5=8F=B7=E5=90=8D=E7=A7=B0?= =?UTF-8?q?=E7=94=9F=E6=88=90=E4=BA=8C=E7=BB=B4=E7=A0=81=E7=9A=84=E5=8A=9F?= =?UTF-8?q?=E8=83=BD=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=89=93=E5=8D=B0=E4=BA=8C?= =?UTF-8?q?=E7=BB=B4=E7=A0=81=E5=8A=9F=E8=83=BD=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/__manifest__.py | 1 + sf_manufacturing/models/stock.py | 56 +++++++++++++++++++ sf_manufacturing/views/stock_lot_views.xml | 18 ++++++ .../models/maintenance_equipment.py | 31 ---------- .../views/tool_material_search.xml | 1 - 5 files changed, 75 insertions(+), 32 deletions(-) create mode 100644 sf_manufacturing/views/stock_lot_views.xml diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 3834e25f..6a122097 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -17,6 +17,7 @@ 'security/ir.model.access.csv', 'wizard/workpiece_delivery_views.xml', 'views/mrp_views_menus.xml', + 'views/stock_lot_views.xml', 'views/mrp_production_addional_change.xml', 'views/mrp_routing_workcenter_view.xml', 'views/production_line_view.xml', diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index f13abf6b..5cb51953 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -1,5 +1,6 @@ # -*- coding: utf-8 -*- import base64 +import qrcode from collections import defaultdict, namedtuple import logging import json @@ -12,6 +13,7 @@ from odoo.tools import float_compare from odoo.addons.stock.models.stock_rule import ProcurementException from odoo.addons.sf_base.commons.common import Common from odoo.exceptions import UserError +from io import BytesIO class StockRule(models.Model): @@ -264,6 +266,60 @@ class ProductionLot(models.Model): return "%s-%s-%03d" % (product.cutting_tool_model_id.code, now, 1) return "%s-%03d" % (product.name, 1) + qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code') + + @api.depends('name') + def _generate_qr_code(self): + for record in self: + # Generate QR code + qr = qrcode.QRCode( + version=1, + error_correction=qrcode.constants.ERROR_CORRECT_L, + box_size=10, + border=4, + ) + qr.add_data(record.name) + qr.make(fit=True) + qr_image = qr.make_image(fill_color="black", back_color="white") + + # Encode the image data in base64 + image_stream = BytesIO() + qr_image.save(image_stream, format="PNG") + encoded_image = base64.b64encode(image_stream.getvalue()) + + record.qr_code_image = encoded_image + + def print_qr_code(self): + self.ensure_one() # 确保这个方法只为一个记录调用 + # if not self.lot_id: + # raise UserError("没有找到序列号。") + # 假设_lot_qr_code方法已经生成了二维码并保存在字段中 + qr_code_data = self.qr_code_image + if not qr_code_data: + raise UserError("没有找到二维码数据。") + + # 生成下载链接或直接触发下载 + # 此处的实现依赖于你的具体需求,以下是触发下载的一种示例 + attachment = self.env['ir.attachment'].sudo().create({ + 'datas': self.qr_code_image, + 'type': 'binary', + 'description': '二维码图片', + 'name': self.name + '.png', + # 'res_id': invoice.id, + # 'res_model': 'stock.picking', + 'public': True, + 'mimetype': 'application/x-png', + # 'model_name': 'stock.picking', + }) + # 返回附件的下载链接 + download_url = '/web/content/%s?download=true' % attachment.id + base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url') + return { + 'type': 'ir.actions.act_url', + 'url': str(base_url) + download_url, + 'target': 'self', + } + class StockPicking(models.Model): _inherit = 'stock.picking' diff --git a/sf_manufacturing/views/stock_lot_views.xml b/sf_manufacturing/views/stock_lot_views.xml new file mode 100644 index 00000000..f637d401 --- /dev/null +++ b/sf_manufacturing/views/stock_lot_views.xml @@ -0,0 +1,18 @@ + + + + stock.lot.form.quality + stock.lot + + + + + + +
+
+
+
+
+
\ No newline at end of file diff --git a/sf_tool_management/models/maintenance_equipment.py b/sf_tool_management/models/maintenance_equipment.py index eb2f5990..4b5fe89e 100644 --- a/sf_tool_management/models/maintenance_equipment.py +++ b/sf_tool_management/models/maintenance_equipment.py @@ -1,8 +1,5 @@ -import qrcode -import base64 from odoo import models, api, fields from odoo.exceptions import ValidationError -from io import BytesIO class SfMaintenanceEquipmentTool(models.Model): @@ -82,34 +79,6 @@ class StockLot(models.Model): record.tool_material_search_id = tool_material_search return records - qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code') - - @api.depends('name') - def _generate_qr_code(self): - for record in self: - # Generate QR code - qr = qrcode.QRCode( - version=1, - error_correction=qrcode.constants.ERROR_CORRECT_L, - box_size=10, - border=4, - ) - qr.add_data(record.name) - qr.make(fit=True) - - # Create an image from the QR Code instance - qr_image = qr.make_image(fill_color="black", back_color="white") - - # Save the image to a BytesIO object - image_stream = BytesIO() - qr_image.save(image_stream, format="PNG") - - # Store the BytesIO object in the binary field - record.qr_code_image = base64.b64decode(image_stream.getvalue()) - # record.qr_code_image = image_stream.getvalue() - - print(record.qr_code_image) - class ProductProduct(models.Model): _inherit = 'product.product' diff --git a/sf_tool_management/views/tool_material_search.xml b/sf_tool_management/views/tool_material_search.xml index 85b3fd47..158e83b9 100644 --- a/sf_tool_management/views/tool_material_search.xml +++ b/sf_tool_management/views/tool_material_search.xml @@ -59,7 +59,6 @@ -
From 5646cc492ee3204bc54090912dc2da2cf54bb650 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Tue, 20 Feb 2024 17:33:06 +0800 Subject: [PATCH 11/17] =?UTF-8?q?1.=E5=BF=AB=E9=80=9F=E8=AE=A2=E5=8D=95?= =?UTF-8?q?=E6=96=B0=E5=A2=9E=E7=89=B9=E5=BE=81=E8=AF=86=E5=88=AB=E8=B7=AF?= =?UTF-8?q?=E5=BE=84=E5=AD=97=E6=AE=B5=202.=E4=BF=AE=E5=A4=8D=E9=94=80?= =?UTF-8?q?=E5=94=AE=E7=BB=8F=E7=90=86=E5=92=8C=E9=94=80=E5=94=AE=E6=80=BB?= =?UTF-8?q?=E7=9B=91=E7=9C=8B=E4=B8=8D=E5=88=B0=E5=BF=AB=E9=80=9F=E8=AE=A2?= =?UTF-8?q?=E5=8D=95=E8=8F=9C=E5=8D=95=203.=E4=BC=98=E5=8C=96=E7=B3=BB?= =?UTF-8?q?=E7=BB=9F=E8=AE=BE=E7=BD=AE=E9=A1=B5=E9=9D=A2=EF=BC=8C=E6=96=B0?= =?UTF-8?q?=E5=A2=9E=E7=89=B9=E5=BE=81=E8=AF=86=E5=88=AB=E8=B7=AF=E5=BE=84?= =?UTF-8?q?=E5=B1=95=E7=A4=BA=EF=BC=8C=E5=8E=BB=E6=8E=89=E9=87=8D=E5=A4=8D?= =?UTF-8?q?=E7=9A=84=E4=B8=9A=E5=8A=A1=E5=B9=B3=E5=8F=B0=E5=8F=82=E6=95=B0?= =?UTF-8?q?=E9=85=8D=E7=BD=AE=E5=B1=95=E7=A4=BA=204.=E5=BF=AB=E9=80=9F?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E5=8E=BB=E6=8E=89=E8=80=81=E7=89=88=E6=9C=AC?= =?UTF-8?q?=E7=9A=84=E7=89=B9=E5=BE=81=E8=AF=86=E5=88=AB=E7=9A=84=E4=BB=A3?= =?UTF-8?q?=E7=A0=81=E5=8F=8A=E5=8C=85=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=9C=80?= =?UTF-8?q?=E6=96=B0=E7=9A=84=E7=89=B9=E5=BE=81=E8=AF=86=E5=88=AB=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../views/res_config_settings_views.xml | 6 +- sf_mrs_connect/models/res_config_setting.py | 2 +- .../views/res_config_settings_views.xml | 14 +- sf_sale/models/__init__.py | 3 + sf_sale/models/feature.sqlite | 0 .../models/parser_and_calculate_work_time.py | 472 ++++++++++++++++++ sf_sale/models/preload_datas_functions.py | 201 ++++++++ sf_sale/models/price.sqlite | 0 sf_sale/models/process_time.db | 0 sf_sale/models/quick_easy_order.py | 180 ++++++- sf_sale/security/ir.model.access.csv | 4 +- 11 files changed, 843 insertions(+), 39 deletions(-) delete mode 100644 sf_sale/models/feature.sqlite create mode 100644 sf_sale/models/parser_and_calculate_work_time.py create mode 100644 sf_sale/models/preload_datas_functions.py delete mode 100644 sf_sale/models/price.sqlite delete mode 100644 sf_sale/models/process_time.db diff --git a/sf_machine_connect/views/res_config_settings_views.xml b/sf_machine_connect/views/res_config_settings_views.xml index bdd481ac..01067754 100644 --- a/sf_machine_connect/views/res_config_settings_views.xml +++ b/sf_machine_connect/views/res_config_settings_views.xml @@ -8,14 +8,14 @@
-

bfm环境配置

+

业务平台参数配置

-
diff --git a/sf_mrs_connect/models/res_config_setting.py b/sf_mrs_connect/models/res_config_setting.py index 3f2b698f..b15c71df 100644 --- a/sf_mrs_connect/models/res_config_setting.py +++ b/sf_mrs_connect/models/res_config_setting.py @@ -13,8 +13,8 @@ class ResConfigSettings(models.TransientModel): token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003') sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6') sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com') - bfm_url = fields.Char(string='业务平台后端访问地址', default='https://bfm.jikimo.com') agv_url = fields.Char(string='avg访问地址', default='http://IP:PORT/rcms/services/rest') + model_parser_url = fields.Char('特征识别路径') ftp_host = fields.Char(string='FTP的ip') ftp_port = fields.Char(string='FTP端口') ftp_user = fields.Char(string='FTP用户') diff --git a/sf_mrs_connect/views/res_config_settings_views.xml b/sf_mrs_connect/views/res_config_settings_views.xml index bc829b2f..08812f23 100644 --- a/sf_mrs_connect/views/res_config_settings_views.xml +++ b/sf_mrs_connect/views/res_config_settings_views.xml @@ -8,8 +8,8 @@
-

同步参数配置

-
+

云平台参数配置

+
@@ -36,7 +36,7 @@

FTP参数配置

-
+
@@ -61,14 +61,14 @@
-

业务平台参数配置

-
+

特征识别参数配置

+
-
diff --git a/sf_sale/models/__init__.py b/sf_sale/models/__init__.py index d8b09a48..99b143c7 100644 --- a/sf_sale/models/__init__.py +++ b/sf_sale/models/__init__.py @@ -1,3 +1,6 @@ from . import sale_order from . import quick_easy_order from . import auto_quatotion_common +from . import parser_and_calculate_work_time +from . import preload_datas_functions + diff --git a/sf_sale/models/feature.sqlite b/sf_sale/models/feature.sqlite deleted file mode 100644 index e69de29b..00000000 diff --git a/sf_sale/models/parser_and_calculate_work_time.py b/sf_sale/models/parser_and_calculate_work_time.py new file mode 100644 index 00000000..f5abcb7f --- /dev/null +++ b/sf_sale/models/parser_and_calculate_work_time.py @@ -0,0 +1,472 @@ +import time +# import pandas as pd +from lxml import etree +from collections import Counter +from . import preload_datas_functions as preload + + +# import preload_datas_functions as preload + + +class FeatureParser: + """ + 解析Feature.xml文件 + """ + + def __init__(self, xml_file): + self.root = etree.parse(xml_file).getroot() + self.size = self._get_size() + self.holes = self._get_holes() + self.slots = self._get_slot() + self.open_slots = self._get_open_slot() + self.vectors = self._get_vectors() + + def _get_size(self): + size = self.root.find('Size') + return { + 'length': float(size.get('Length')), + 'width': float(size.get('Width')), + 'height': float(size.get('Height')) + } + + def _get_vectors(self): + vectors = {} + for item in self.root.findall('.//Item'): + vector = item.find('Vector') + if vector is not None: + key = (vector.get('i'), vector.get('j'), vector.get('k')) + vectors[key] = vectors.get(key, 0) + 1 + return vectors + + def get_vector_counts(self): + return len(self.vectors) + + def _get_holes(self): + holes = [] + hole_element = self.root.find('Hole') + if hole_element is not None: + for item in self.root.find('Hole').iter('Item'): + hole = {} # 每个hole是一个字典 + hole['id'] = int(item.get('ID')) + hole['name'] = item.get('Name') + hole['red'] = int(item.get('Red')) + hole['green'] = int(item.get('Green')) + hole['blue'] = int(item.get('Blue')) + # 处理circles + circles = [] + for circle in item.iter('Circle'): + circles.append({ + 'x': float(circle.get('x')), + 'y': float(circle.get('y')), + 'z': float(circle.get('z')), + 'rad': float(circle.get('rad')) + }) + hole['circles'] = circles + + # 处理bottom + bottoms = [] + for bottom in item.iter('Bottom'): + bottoms.append({ + 'x': float(bottom.get('x')), + 'y': float(bottom.get('y')), + 'z': float(bottom.get('z')), + 'rad': float(bottom.get('rad')) + }) + hole['bottoms'] = bottoms + + # 处理vector + for vector in item.iter('Vector'): + hole['vector'] = { + 'i': float(vector.get('i')), + 'j': float(vector.get('j')), + 'k': float(vector.get('k')) + } + + # 创建元组并添加到列表中 + z_rad_tuples = [] + max_z = None + non_zero_rads = set() # 使用set来存储rad值,自动去重 + for circle in circles: + z = float(circle.get('z')) + rad = float(circle.get('rad')) + if max_z is None or z > max_z: + max_z = z + if rad != 0: + non_zero_rads.add(rad) + for rad in non_zero_rads: + z_rad_tuple = (max_z, rad) + z_rad_tuples.append(z_rad_tuple) + hole['z_rad_tuples'] = z_rad_tuples + + holes.append(hole) # 添加到holes列表中 + + return holes + + def _get_slot(self): + """ + 获取slot信息 + """ + slots = [] + slot_a_list = [] + slot_element = self.root.find('Slot') + if slot_element is not None: + for item in self.root.find('Slot').iter('Item'): + slot = {} + slot['id'] = int(item.get('ID')) + slot['name'] = item.get('Name') + slot['red'] = int(item.get('Red')) + slot['green'] = int(item.get('Green')) + slot['blue'] = int(item.get('Blue')) + # 获取Volume和Area信息 + volume = item.find('Volume') + if volume is not None: + slot['volume'] = float(volume.get('value')) + + area = item.find('Area') + if area is not None: + slot['area'] = float(area.get('value')) + slot_a_list.append(slot['area']) + # 处理lines + lines = [] + for line in item.iter('Line'): + lines.append({ + 'type': line.get('Type'), # 'type' : 'line' or 'arc + 'x1': float(line.get('x1')), + 'y1': float(line.get('y1')), + 'z1': float(line.get('z1')), + 'x2': float(line.get('x2')), + 'y2': float(line.get('y2')), + 'z2': float(line.get('z2')) + }) + slot['lines'] = lines + + # 处理Arc + arcs = [] + for arc in item.iter('Arc'): + arcs.append({ + 'type': arc.get('Type'), + 'x1': float(arc.get('x1')), + 'y1': float(arc.get('y1')), + 'z1': float(arc.get('z1')), + 'x2': float(arc.get('x2')), + 'y2': float(arc.get('y2')), + 'z2': float(arc.get('z2')), + 'x3': float(arc.get('x3')), + 'y3': float(arc.get('y3')), + 'z3': float(arc.get('z3')) + + }) + slot['arcs'] = arcs + slot['a'] = slot_a_list + slots.append(slot) + return slots + + def _get_open_slot(self): + """ + 获取open_slot信息 + """ + open_slots = [] + open_slot_v_list = [] + open_slot_element = self.root.find('OpenSlot') + if open_slot_element is not None: + for item in self.root.find('OpenSlot').iter('Item'): + open_slot = {} + open_slot['id'] = int(item.get('ID')) + open_slot['name'] = item.get('Name') + open_slot['red'] = int(item.get('Red')) + open_slot['green'] = int(item.get('Green')) + open_slot['blue'] = int(item.get('Blue')) + # 获取Volume和Area信息 + volume = item.find('Volume') + if volume is not None: + open_slot['volume'] = float(volume.get('value')) + + area = item.find('Area') + if area is not None: + open_slot['area'] = float(area.get('value')) + # open_slot_v_list.append(round(open_slot['volume'] / open_slot['area'], 3)) + open_slot_v_list.append(open_slot['area']) + # 处理lines + lines = [] + for line in item.iter('Line'): + lines.append({ + 'type': line.get('Type'), # 'type' : 'line' or 'arc + 'x1': float(line.get('x1')), + 'y1': float(line.get('y1')), + 'z1': float(line.get('z1')), + 'x2': float(line.get('x2')), + 'y2': float(line.get('y2')), + 'z2': float(line.get('z2')) + }) + open_slot['lines'] = lines + + # 处理Arc + arcs = [] + for arc in item.iter('Arc'): + arcs.append({ + 'type': arc.get('Type'), + 'x1': float(arc.get('x1')), + 'y1': float(arc.get('y1')), + 'z1': float(arc.get('z1')), + 'x2': float(arc.get('x2')), + 'y2': float(arc.get('y2')), + 'z2': float(arc.get('z2')), + 'x3': float(arc.get('x3')), + 'y3': float(arc.get('y3')), + 'z3': float(arc.get('z3')) + + }) + open_slot['arcs'] = arcs + open_slot['v'] = open_slot_v_list + open_slots.append(open_slot) + return open_slots + + +def hole_time(parser): + """ + 计算孔的工时 + :return: + """ + # 判断是否有孔 + if parser.holes is not None: + # 遍历所有的孔,获取孔径和孔深度,然后调用函数查询工时 + hole_total_time = 0 + nums = 1 + expand_hole = '否' + j_time = 0 + j_hole_nums = 0 + hole_nums = 0 + for hole in parser.holes: + for z_rad_tuple in hole['z_rad_tuples']: + if (2 * z_rad_tuple[1] * z_rad_tuple[0] <= 3750) and (2 * z_rad_tuple[1] <= 25): + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = preload.get_suitable_hole_working_hours(preload.df_hole_duration, + 2 * z_rad_tuple[1], + z_rad_tuple[0]) + # if per_time_minute is None: + # raise Exception('孔径为%s,深度为%s的孔没有找到对应的工时' % (2 * z_rad_tuple[1], z_rad_tuple[0])) + # print('per_time_minute', per_time_minute) + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + elif (2 * z_rad_tuple[1] * z_rad_tuple[0] <= 3750) and (2 * z_rad_tuple[1] > 25): + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = 0.0003 * 2 * z_rad_tuple[1] * z_rad_tuple[0] + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + elif 3750 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 50000: + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = 0.0003 * 2 * z_rad_tuple[1] * z_rad_tuple[0] + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + elif 50000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 100000: + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = 0.00018 * 2 * z_rad_tuple[1] * z_rad_tuple[0] + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + elif 100000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 150000: + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = 0.00016 * 2 * z_rad_tuple[1] * z_rad_tuple[0] + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + elif 150000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 200000: + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = 0.00015 * 2 * z_rad_tuple[1] * z_rad_tuple[0] + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + elif 200000 < 2 * z_rad_tuple[1] * z_rad_tuple[0] <= 250000: + hole_nums += 1 + # print('z_rad_tuple', z_rad_tuple) + per_time_minute = 0.0002 * 2 * z_rad_tuple[1] * z_rad_tuple[0] + expand_hole_end = 0.6 if expand_hole == '是' else 1 + per_time = (per_time_minute * 1 * expand_hole_end + j_time * j_hole_nums * expand_hole_end) / 60 + hole_total_time += per_time + else: + raise Exception('孔径为%s,深度为%s的孔没有找到对应的工时' % (2 * z_rad_tuple[1], z_rad_tuple[0])) + + print('孔工时', round(hole_total_time * nums * 2) / 2) + print('共有%s个孔,其中%s为台阶孔' % (len(parser.holes), hole_nums - len(parser.holes))) + return round(hole_total_time * nums * 2) / 2 + else: + return 0 + + +def slot_time(parser): + # 判断是否有槽 + if parser.slots is not None: + # 遍历所有的槽,获取槽的长度,然后调用函数查询工时 + slot_total_time = 0 + nums = 1 + finish_time = 0 + process_time = 0 + process_total_time = 0 + slot_a = parser.slots[0]['a'] + + slot_a_counter = Counter(slot_a) + slot_a_counter_result = dict(slot_a_counter) + + for i in slot_a_counter_result: + for slot in parser.slots: + if slot['area'] == i: + # # 计算长度(第一条线和第三条线的X轴距离) + # length = abs(slot['lines'][0]['y1'] - slot['lines'][2]['y1']) + # # 计算宽度(第一条线和第二条线的Y轴距离) + # width = abs(slot['lines'][1]['x1'] - slot['lines'][3]['x1']) + # # 计算面积 + # area = length * width + # 槽深度 + depth = round(slot['volume'] / slot['area'], 3) + + # 沟通刀具暂定为12 + finish_tool_diameter = 12 + if 200 < slot['area'] <= 5000: + finish_time = 0 + + # 加工穴数待定(取得每一个槽的穴数和装夹次数,那这个数量?目前暂时按1来算,待有统计数据之后再说) + rough_part_nums = slot_a_counter_result[slot['area']] + rough_clamping_times = 1 + finishi_part_nums = 1 + finish_clamping_times = 1 + # 调用函数计算槽的工时 + slot_total_time = preload.get_suitable_rough_working_hours(preload.df_rough_duration, depth) + # if nums > 20: + # process_time = round( + # (nums * 0.6 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # elif nums > 10: + # process_time = round( + # (nums * 0.7 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # elif nums > 6: + # process_time = round( + # (nums * 0.8 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # elif nums > 4: + # process_time = round( + # (nums * 0.9 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # elif nums > 1: + # process_time = round( + # (nums * 0.95 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # else: + # process_time = round( + # (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + # finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + process_time = round( + (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # print('slot_total_time', slot_total_time) + elif slot['area'] <= 200: + slot_total_time = 0 + rough_part_nums = slot_a_counter_result[slot['area']] + rough_clamping_times = 1 + finishi_part_nums = 1 + finish_clamping_times = 1 + # 调用函数计算槽的工时 + finish_time = preload.get_suitable_finish_working_hours(preload.df_finish_duration, depth, + finish_tool_diameter) + process_time = round( + (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # print('finish_time', finish_time) + else: + rough_part_nums = slot_a_counter_result[slot['area']] + rough_clamping_times = 1 + finishi_part_nums = 1 + finish_clamping_times = 1 + process_time = round( + (nums * 1 * ((0.00016 * rough_part_nums + rough_clamping_times * 20) + ( + finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + process_total_time += process_time + + print('槽工时', process_total_time) + return process_total_time + else: + return 0 + + +def open_slot_time(parser): + # 判断是否有开口槽 + if parser.open_slots is not None: + # 遍历所有的开口槽,获取槽宽和槽长,然后调用函数查询工时 + open_slot_total_time = 0 + nums = 1 + finish_time = 0 + open_slot_process_time = 0 + + open_slot_v = parser.open_slots[0]['v'] + + counter = Counter(open_slot_v) + result = dict(counter) + + transiant_time = 0 + for i in result: + for open_slot in parser.open_slots: + if open_slot['area'] == i: + depth = round(open_slot['volume'] / open_slot['area'], 3) + # 沟通刀具暂定为12 + finish_tool_diameter = 12 + if 200 < open_slot['area'] <= 5000: + finish_time = 0 + # 加工穴数待定(取得每一个槽的穴数和装夹次数,那这个数量?目前暂时按1来算,待有统计数据之后再说) + rough_part_nums = result[open_slot['area']] + rough_clamping_times = 1 + finishi_part_nums = 1 + finish_clamping_times = 1 + # 调用函数计算槽的工时 + slot_total_time = preload.get_suitable_rough_working_hours(preload.df_rough_duration, depth) + open_slot_process_time = round( + (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # print('slot_total_time', slot_total_time) + elif open_slot['area'] <= 200: + slot_total_time = 0 + rough_part_nums = 1 + rough_clamping_times = 1 + finishi_part_nums = 1 + finish_clamping_times = 1 + # 调用函数计算槽的工时 + finish_time = preload.get_suitable_finish_working_hours(preload.df_finish_duration, depth, + finish_tool_diameter) + open_slot_process_time = round( + (nums * 1 * ((slot_total_time * rough_part_nums + rough_clamping_times * 20) + ( + finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + # print('finish_time', finish_time) + else: + rough_part_nums = 1 + rough_clamping_times = 1 + finishi_part_nums = 1 + finish_clamping_times = 1 + open_slot_process_time = round( + (nums * 1 * ((0.00016 * rough_part_nums + rough_clamping_times * 20) + ( + finish_time * finishi_part_nums + finish_clamping_times * 25)) / 60) * 2) / 2 + + transiant_time += open_slot_process_time + print('开口槽工时', transiant_time) + return transiant_time + else: + return 0 + + +if __name__ == '__main__': + time1 = time.time() + parser = FeatureParser( + 'D:\\ccccccccccccccccccccccccccccccccccccccccccccccc\\aa\\JKM001-260.200.30_FeatureTable.xml') + # print('parser', parser.holes) + # print('parser.slots', parser.slots) + # print('parser.open_slots', parser.open_slots) + print('总工时', hole_time(parser) + slot_time(parser) + open_slot_time(parser)) + time2 = time.time() + print('耗时:', time2 - time1) diff --git a/sf_sale/models/preload_datas_functions.py b/sf_sale/models/preload_datas_functions.py new file mode 100644 index 00000000..37035f44 --- /dev/null +++ b/sf_sale/models/preload_datas_functions.py @@ -0,0 +1,201 @@ +import psycopg2 +# import pandas as pd + + +def load_and_convert_data(table_name, column_names): + connection = None + data = [] + + try: + # connection = psycopg2.connect(user="odoo", + # password="odoo", + # host="localhost", + # port="5432", + # database="www1") + connection = psycopg2.connect(user="odoo", + password="odoo", + host="120.76.195.146", + port="15432", + database="bfm_dev1") + + cursor = connection.cursor() + + # Construct the query string using the table name passed in + query = f"SELECT {', '.join(column_names)} FROM {table_name};" + cursor.execute(query) + + # Fetch all rows from cursor + data = cursor.fetchall() + + except (Exception, psycopg2.Error) as error: + print("Error fetching data from PostgreSQL table", error) + + finally: + # Always close database connection after work done + if (connection): + cursor.close() + connection.close() + + # Convert the list of tuples to DataFrame + # df = pd.DataFrame(data, columns=column_names) + # + # # Convert all string columns to float + # for col in df.columns: + # if df[col].dtype == 'object': + # df[col] = df[col].astype(float) + + return 'df' + + +def get_suitable_hole_working_hours(df, target_diameter, target_depth): + """ + 从钻孔、铰孔数据中获取符合要求的最小工时 + """ + # df为输入的数据,target_diameter为目标孔径,target_depth为目标孔深 + + df_diameter_filtered = df.loc[df['hole_diameter'] >= target_diameter] + + if not df_diameter_filtered.empty: + min_diameter = df_diameter_filtered['hole_diameter'].min() + df_depth_filtered = df_diameter_filtered.loc[ + (df_diameter_filtered['hole_diameter'] == min_diameter) & ( + df_diameter_filtered['hole_depth'] >= target_depth)] + + if not df_depth_filtered.empty: + min_depth_row = df_depth_filtered.loc[df_depth_filtered['hole_depth'].idxmin()] + min_working_hours = min_depth_row['working_hours'] + return min_working_hours + else: + print("No records found where hole_depth is bigger than the target depth") + return None + else: + print("No records found where hole_diameter is bigger than the target diameter") + return None + + +def get_suitable_blank_working_hours(df, blank_height, blank_length, blank_width): + """ + 从毛坯数据中获取符合要求的最小工时 + """ + # df为输入的数据,blank_height为目标毛坯高度,blank_length为目标毛坯长度,blank_width为目标毛坯宽度 + + df_height_filtered = df.loc[df['blank_height'] >= blank_height] + + if not df_height_filtered.empty: + min_height = df_height_filtered['blank_height'].min() + df_length_filtered = df_height_filtered.loc[ + (df_height_filtered['blank_height'] == min_height) & ( + df_height_filtered['blank_length'] >= blank_length)] + + if not df_length_filtered.empty: + min_length_row = df_length_filtered.loc[df_length_filtered['blank_length'].idxmin()] + min_working_hours = min_length_row['working_hours'] + return min_working_hours + else: + print("No records found where blank_length is bigger than the target length") + return None + else: + print("No records found where blank_height is bigger than the target height") + return None + + +def get_suitable_rough_working_hours(df, rough_depth): + """ + 从粗加工数据中获取符合要求的最小工时 + """ + # df为输入的数据,rough_depth为目标粗加工深度 + + df_depth_filtered = df.loc[df['rough_depth'] >= rough_depth] + + if not df_depth_filtered.empty: + min_depth_row = df_depth_filtered.loc[df_depth_filtered['rough_depth'].idxmin()] + min_working_hours = min_depth_row['working_hours'] + return min_working_hours + else: + print("No records found where rough_depth is bigger than the target depth") + return None + + +def get_suitable_finish_working_hours(df, finish_depth, finish_tool_diameter): + """ + 从精加工数据中获取符合要求的最小工时 + """ + # df为输入的数据,finish_depth为目标精加工深度,finish_tool_diameter为目标精加工刀具直径 + + df_depth_filtered = df.loc[df['finish_depth'] >= finish_depth] + + if not df_depth_filtered.empty: + min_depth = df_depth_filtered['finish_depth'].min() + df_tool_diameter_filtered = df_depth_filtered.loc[ + (df_depth_filtered['finish_depth'] == min_depth) & ( + df_depth_filtered['finish_tool_diameter'] >= finish_tool_diameter)] + + if not df_tool_diameter_filtered.empty: + min_tool_diameter_row = df_tool_diameter_filtered.loc[ + df_tool_diameter_filtered['finish_tool_diameter'].idxmin()] + min_working_hours = min_tool_diameter_row['working_hours'] + return min_working_hours + else: + print("No records found where finish_tool_diameter is bigger than the target tool diameter") + return None + else: + print("No records found where finish_depth is bigger than the target depth") + return None + + +def get_suitable_chamfer_working_hours(df, chamfer_length, chamfer_size): + """ + 根据倒角长度获得倒角工时,装夹平面耗时clamping_type_plane和装夹斜面耗时clamping_type_slope + """ + # df为输入的数据,chamfer_length为目标倒角长度,clamping_type_plane为目标装夹平面耗时,clamping_type_slope为目标装夹斜面耗时 + + df_length_filtered = df.loc[df['chamfer_length'] >= chamfer_length] + df_chamfer_size_filtered = df.loc[df['chamfer_size'] >= chamfer_size] + + if not df_length_filtered.empty and not df_chamfer_size_filtered.empty: + min_length_row = df_length_filtered.loc[df_length_filtered['chamfer_length'].idxmin()] + min_chamfer_size_row = df_chamfer_size_filtered.loc[df_chamfer_size_filtered['chamfer_size'].idxmin()] + clamping_time = min_length_row['clamping_time'] + clamping_type_plane = min_length_row['clamping_type_plane'] + clamping_type_slope = min_length_row['clamping_type_slope'] + coefficient = min_chamfer_size_row['coefficient'] + return clamping_time, clamping_type_plane, clamping_type_slope, coefficient + else: + print("No records found where chamfer_length is bigger than the target length") + return None + + +df_hole_duration = load_and_convert_data('hole_duration', ['hole_diameter', 'hole_depth', 'working_hours']) + +df_j_hole_duration = load_and_convert_data('j_hole_duration', ['hole_diameter', 'hole_depth', 'working_hours']) + +df_chamfer_duration = load_and_convert_data('chamfer_duration', + ['chamfer_length', 'clamping_time', 'chamfer_size', 'coefficient', + 'clamping_type_plane', 'clamping_type_slope']) + +df_blank_duration = load_and_convert_data('blank_duration', + ['blank_length', 'blank_width', 'blank_height', 'working_hours']) + +df_rough_duration = load_and_convert_data('rough_duration', ['rough_depth', 'working_hours']) + +df_finish_duration = load_and_convert_data('finish_duration', + ['finish_depth', 'finish_tool_diameter', 'working_hours']) + + +if __name__ == '__main__': + min_working_hours = get_suitable_hole_working_hours(df_hole_duration, 24, 150) + print('min_working_hours', min_working_hours) + min_j_working_hours = get_suitable_hole_working_hours(df_j_hole_duration, 10, 15) + print('min_j_working_hours', min_j_working_hours) + min_blank_working_hours = get_suitable_blank_working_hours(df_blank_duration, 150, 300, 300) + print('min_blank_working_hours', min_blank_working_hours) + min_rough_working_hours = get_suitable_rough_working_hours(df_rough_duration, 49) + print('min_rough_working_hours', min_rough_working_hours) + min_finish_working_hours = get_suitable_finish_working_hours(df_finish_duration, 0.5, 10) + print('min_finish_working_hours', min_finish_working_hours) + clamping_time, clamping_type_plane, clamping_type_slope, coefficient = get_suitable_chamfer_working_hours( + df_chamfer_duration, 10, 1.5) + print('clamping_time', clamping_time) + print('clamping_type_plane', clamping_type_plane) + print('clamping_type_slope', clamping_type_slope) + print('coefficient', coefficient) diff --git a/sf_sale/models/price.sqlite b/sf_sale/models/price.sqlite deleted file mode 100644 index e69de29b..00000000 diff --git a/sf_sale/models/process_time.db b/sf_sale/models/process_time.db deleted file mode 100644 index e69de29b..00000000 diff --git a/sf_sale/models/quick_easy_order.py b/sf_sale/models/quick_easy_order.py index 1e5f274c..7e6b8c78 100644 --- a/sf_sale/models/quick_easy_order.py +++ b/sf_sale/models/quick_easy_order.py @@ -2,17 +2,19 @@ import logging import base64 import hashlib import os +import platform import json from datetime import datetime import requests -from OCC.Extend.DataExchange import read_step_file -from OCC.Extend.DataExchange import write_stl_file +from odoo import http +from odoo.http import request +# from OCC.Extend.DataExchange import read_step_file +# from OCC.Extend.DataExchange import write_stl_file from odoo import models, fields, api from odoo.modules import get_resource_path from odoo.exceptions import ValidationError, UserError from odoo.addons.sf_base.commons.common import Common - - +from . import parser_and_calculate_work_time as pc @@ -77,11 +79,11 @@ class QuickEasyOrder(models.Model): 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) + # 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.model_analyze(attachment) # logging.info('create-model_file:%s' % len(vals['model_file'])) obj = super(QuickEasyOrder, self).create(vals) @@ -91,6 +93,147 @@ class QuickEasyOrder(models.Model): obj.state = '待接单' return obj + + def model_analyze(self,model_attachment): + """ + step模型解析,上传模型时转为web可显示的格式 + :return: + """ + config = request.env['res.config.settings'].sudo().get_values() + try: + # 获取当前操作系统 + os_name = platform.system() + for item in model_attachment: + # 将拿到的3D模型数据存入文件 + # 定义文件名和文件的二进制内容 + file_name = item.name # 请将这里替换为你的文件名 + print('file_name', file_name) + # base64_data = base64.b64encode(item.datas) + # base64_datas = base64_data.decode('utf-8') + binary_content = item.datas # 请将这里替换为你的文件的二进制内容 + # binary_content从字符串转为二进制 + binary_content = base64.b64decode(binary_content) + # 定义新的文件夹路径 + # 根据操作系统不同,文件路径不同 + path_header = '/model_parser' if os_name == 'Linux' else 'D:/model_analysis' + # new_folder_path = 'D:/11111final' + '/' + item['name'].split(".")[0] + new_folder_path = path_header + '/' + item.name.rpartition('.')[0] + print('new_folder_path', new_folder_path) + # 检查新的文件夹是否存在,如果不存在,则创建 + if not os.path.exists(new_folder_path): + os.makedirs(new_folder_path) + # 定义新的文件路径 + new_file_path = os.path.join(new_folder_path, file_name) + # 将二进制内容写入新的文件 + with open(new_file_path, 'wb') as f: + f.write(binary_content) + # 检查文件是否已经成功写入 + if os.path.exists(new_file_path): + print(f'Successfully wrote binary content to {new_file_path}') + else: + print(f'Failed to write binary content to {new_file_path}') + # 附件 + # attachment = request.env['ir.attachment'].sudo().create({ + # 'datas': item['data'].encode('utf-8'), + # 'type': 'binary', + # 'description': '模型文件', + # 'name': item['name'], + # 'public': True, + # 'model_name': item['name'], + # }) + headers = {'Content-Type': 'application/json'} + # 调用写入宿主机接口 + # url_dir = 'http://192.168.50.202:8000/create_and_write_file' + url_dir = config['model_parser_url'] + '/create_and_write_file' + data = { + 'folder_path': new_folder_path, # 您想要创建的文件夹路径 + 'file_path': new_file_path, # 您想要创建的文件名 + 'content': item['data'] # 您想要写入文件的内容 + } + requests.post(url_dir, json=data, headers=headers) + # 调用特征包接口 + url = config['model_parser_url'] + '/process_file' + payload = { + 'file_path': new_file_path, + 'dest_path': new_folder_path, + 'back_url': config['bfm_url'] + } + response = requests.post(url, json=payload, headers=headers) + if response.status_code == 200: + print("Request was successful.") + print("Response: ", response.json()) + else: + print("Request failed.") + # 特征识别 + xml_path = new_folder_path + '/' + item.name.rpartition('.')[0] + '_FeatrueTable.XML' + print('xml_path', xml_path) + parser_obj = pc.FeatureParser(xml_path) + print('parser_obj', parser_obj) + slot = parser_obj.slots + print('slot', slot) + hole = parser_obj.holes + print('hole', hole) + size = parser_obj.size + print('size', size) + open_slot = parser_obj.open_slots + print('open_slot', open_slot) + vector = parser_obj.vectors + print('vector', vector) + print('all parcer', size) + try: + hole_time = pc.hole_time(parser_obj) + print('hole_time', hole_time) + except Exception as e: + return json.dumps({'code': 400, 'msg': '孔尺寸超限', 'error_msg': str(e)}) + try: + slot_time = pc.slot_time(parser_obj) + print('slot_time', slot_time) + except Exception as e: + return json.dumps({'code': 400, 'msg': '槽尺寸超限', 'error_msg': str(e)}) + try: + open_slot_time = pc.open_slot_time(parser_obj) + print('open_slot_time', open_slot_time) + except Exception as e: + return json.dumps({'code': 400, 'msg': '开口槽尺寸超限', 'error_msg': str(e)}) + total_time = hole_time + slot_time + open_slot_time + print(hole_time, slot_time, open_slot_time) + print('total_time', total_time) + ret = {'feature_infos': [{'name': 'all_feature', 'type': '铣', 'process_time': total_time}], + 'boxshape': size, 'slugX': 10.0, 'slugY': 90.0, 'slugZ': 42.0, + 'turn_over_times': 2, + 'target_faces': ['A', 'B']} + self.model_feature = json.dumps(ret['feature_infos'], ensure_ascii=False) + self.model_length = size['length'] # 长 单位mm + self.model_width = size['width'] # 宽 + self.model_height = size['height'] # 高 + self.model_volume = size['length'] * size['width'] * size['height'] + # 附件处理 + base64_data = base64.b64encode(item.datas) + base64_datas = base64_data.decode('utf-8') + model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest() + # 读取文件 + shapes = read_step_file(new_file_path) + output_file = os.path.join(new_folder_path, str(model_code) + '.stl') + write_stl_file(shapes, output_file, 'binary', 0.03, 0.5) + # 转化为glb + output_glb_file = os.path.join(new_folder_path, str(model_code) + '.glb') + util_path = get_resource_path('jikimo_gateway_api', 'static/util') + # 根据操作系统确定使用 'python' 还是 'python3' + python_cmd = 'python3' if os_name == 'Linux' else 'python' + print('python_cmd', python_cmd) + print('os_name', os_name) + # 使用引号包围路径 + cmd = '%s "%s/stl2gltf.py" "%s" "%s" -b' % (python_cmd, util_path, output_file, output_glb_file) + logging.info(cmd) + 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 + except Exception as e: + return UserError('模型自动报价失败,请联系管理员') + # 将attach的datas内容转为glb文件 def transition_glb_file(self, report_path, model_code): shapes = read_step_file(report_path) @@ -116,24 +259,7 @@ class QuickEasyOrder(models.Model): 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() - logging.info("模型编码: %s" % model_code) - item.model_file = self.transition_glb_file(report_path, model_code) - ret = self.feature_recognition(report_path, model_code) - logging.info("自动报价返回值: %s" % ret) - boxshape = ret['boxshape'].tolist() - logging.info("自动报价boxshape: %s" % boxshape) - logging.info('自动报价feature_infos:%s' % ret['feature_infos']) - item.model_length = boxshape[0] # 长 单位mm - item.model_width = boxshape[1] # 宽 - item.model_height = boxshape[2] # 高 - item.model_volume = boxshape[0] * boxshape[1] * boxshape[2] - item.model_feature = json.dumps(ret['feature_infos'], ensure_ascii=False) + item.model_file = self.model_analyze(file_attachment_id) self._get_price(item) else: item.model_file = False diff --git a/sf_sale/security/ir.model.access.csv b/sf_sale/security/ir.model.access.csv index 6dc34877..566a7c70 100644 --- a/sf_sale/security/ir.model.access.csv +++ b/sf_sale/security/ir.model.access.csv @@ -1,5 +1,7 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_quick_easy_order,quick_easy_order,model_quick_easy_order,base.group_system,1,1,1,1 +access_quick_easy_order,quick_easy_order,model_quick_easy_order,base.group_system,1,1,1,0 +access_quick_easy_order_group_sale_salemanager,quick_easy_order_group_sale_salemanager,model_quick_easy_order,sf_base.group_sale_salemanager,1,1,1,0 +access_quick_easy_order_group_sale_director,quick_easy_order_group_sale_director,model_quick_easy_order,sf_base.group_sale_director,1,1,1,0 access_sf_auto_quatotion_common,sf_auto_quatotion_common,model_sf_auto_quatotion_common,base.group_system,1,1,1,1 access_sale_order_manager,sale_order_manager,model_sale_order,sf_base.group_sale_salemanager,1,1,1,0 access_sale_order_director,sale_order_director,model_sale_order,sf_base.group_sale_director,1,1,1,0 From 6103bca698fbb41e8642fca36522e36c1b104d46 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 20 Feb 2024 17:35:31 +0800 Subject: [PATCH 12/17] =?UTF-8?q?=E8=B4=A7=E6=9E=B6=E8=B4=A7=E4=BD=8D?= =?UTF-8?q?=E5=AF=B9=E8=B1=A1=E6=8B=86=E5=88=86?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/models/model.py | 166 ++++++++-------- sf_warehouse/security/ir.model.access.csv | 6 +- .../views/change_stock_move_views.xml | 1 - sf_warehouse/views/shelf_location.xml | 185 +++++++++++------- 4 files changed, 201 insertions(+), 157 deletions(-) diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index 02c52392..14db4f8d 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -223,9 +223,82 @@ class SfLocation(models.Model): # return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + i_str + '-' + j_str +class SfShelf(models.Model): + _name = 'sf.shelf' + _description = '货架' + _order = 'name' + + name = fields.Char('货架名称', required=True, size=20) + barcode = fields.Char('编码', copy=False, size=15, required=True) + # 货位 + location_ids = fields.One2many('sf.shelf.location', 'shelf_id', string='货位') + + check_state = fields.Selection([ + ('enable', '启用'), + ('close', '关闭') + ], string='审核状态', default='close') + + def action_check(self): + self.check_state = 'enable' + + # 绑定库区 + shelf_location_id = fields.Many2one('stock.location', string='所属库区') + + # 货架独有字段:通道、方向、货架高度(m)、货架层数、层数容量 + channel = fields.Char(string='通道', required=True, size=10) + direction = fields.Selection([ + ('R', 'R'), + ('L', 'L') + ], string='方向', required=True) + shelf_height = fields.Float(string='货架高度(m)') + shelf_layer = fields.Integer(string='货架层数') + layer_capacity = fields.Integer(string='层数容量') + + @api.onchange('shelf_location_id') + def _onchange_shelf_location_id(self): + """ + 根据货架的所属库区修改货位的所属库区 + """ + if self.name: + all_location = self.env['sf.shelf.location'].search([('name', 'ilike', self.name)]) + for record in self: + for location in all_location: + location.location_id = record.shelf_location_id.id + + def create_location(self): + """ + 当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量 + """ + area_obj = self.env['sf.shelf.location'] + for i in range(self.shelf_layer): + for j in range(self.layer_capacity): + location_name = self.name + '-' + str(i + 1) + '层' + '-' + str(j + 1) + '位置' + # 检查是否已经有同名的位置存在 + existing_location = area_obj.search([('name', '=', location_name)]) + if not existing_location: + area_obj.create({ + 'name': location_name, + 'location_id': self.shelf_location_id.id, + 'barcode': self.generate_barcode(i, j), + 'location_status': '空闲', + 'shelf_id': self.id + }) + + def generate_barcode(self, i, j): + """ + 生成货位条码 + """ + # 这里是你生成barcode的代码 + # area_type_barcode = self.location_id.barcode + area_type_barcode = self.barcode + i_str = str(i + 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 + + class ShelfLocation(models.Model): _name = 'sf.shelf.location' - _description = '货架货位' + _description = '货位' _order = 'name' # current_location_id = fields.Many2one('sf.shelf.location', string='当前位置') @@ -245,8 +318,10 @@ class ShelfLocation(models.Model): if record.location_status == '禁用': record.storage_time = False - name = fields.Char('名称', required=True, size=20) - barcode = fields.Char('编码', copy=False, size=15) + name = fields.Char('货位名称', required=True, size=20) + barcode = fields.Char('货位编码', copy=False, size=15) + # 货架 + shelf_id = fields.Many2one('sf.shelf', string='货架') check_state = fields.Selection([ ('enable', '启用'), @@ -256,27 +331,18 @@ class ShelfLocation(models.Model): def action_check(self): self.check_state = 'enable' - # 仓库类别(selection:库区、库位、货位) - location_type = fields.Selection([ - ('货架', '货架'), - ('货位', '货位') - ], string='存储类型') + # # 仓库类别(selection:库区、库位、货位) + # location_type = fields.Selection([ + # ('货架', '货架'), + # ('货位', '货位') + # ], string='存储类型') # 绑定库区 - shelf_location_id = fields.Many2one('stock.location', string='所属库区', domain=[('location_type', '=', '库区')]) - location_id = fields.Many2one('stock.location', string='所属库区', domain=[('location_type', '=', '库区')]) + # shelf_location_id = fields.Many2one('stock.location', string='所属库区', domain=[('location_type', '=', '库区')]) + location_id = fields.Many2one('stock.location', string='所属库区') # 产品类别 (关联:product.category) # product_type = fields.Many2many('product.category', string='产品类别') # picking_product_type = fields.Many2many('stock.picking', string='调拨产品类别', related='location_dest_id.product_type') - # 货架独有字段:通道、方向、货架高度(m)、货架层数、层数容量 - channel = fields.Char(string='通道') - direction = fields.Selection([ - ('R', 'R'), - ('L', 'L') - ], string='方向') - shelf_height = fields.Float(string='货架高度(m)') - shelf_layer = fields.Integer(string='货架层数') - layer_capacity = fields.Integer(string='层数容量') # 货位独有字段:货位状态、产品(关联产品对象)、产品序列号(关联产品序列号对象) location_status = fields.Selection([ @@ -288,9 +354,6 @@ class ShelfLocation(models.Model): product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', readonly=True) product_sn_id = fields.Many2one('stock.lot', string='产品序列号') - hide_shelf = fields.Boolean(compute='_compute_hide_what', string='隐藏货架') - hide_location = fields.Boolean(compute='_compute_hide_what', string='隐藏货位') - # 修改货位状态为禁用 def action_location_status_disable(self): self.location_status = '禁用' @@ -299,17 +362,6 @@ class ShelfLocation(models.Model): def action_location_status_enable(self): self.location_status = '空闲' - @api.onchange('shelf_location_id') - def _onchange_shelf_location_id(self): - """ - 根据货架的所属库区修改货位的所属库区 - """ - if self.name: - all_location = self.env['sf.shelf.location'].search([('name', 'ilike', self.name)]) - for record in self: - for location in all_location: - location.location_id = record.shelf_location_id.id - @api.depends('product_sn_id') def _compute_product_id(self): """ @@ -321,53 +373,7 @@ class ShelfLocation(models.Model): record.sudo().location_status = '占用' else: record.product_id = False - # record.location_status = '空闲' - - @api.depends('location_type') - def _compute_hide_what(self): - """ - 根据仓库类别,隐藏不需要的字段 - :return: - """ - for record in self: - record.sudo().hide_shelf = False - record.sudo().hide_location = False - if record.location_type and record.location_type == '货架': - record.sudo().hide_shelf = True - elif record.location_type and record.location_type == '货位': - record.sudo().hide_location = True - else: - pass - - def create_location(self): - """ - 当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量 - """ - if self.location_type == '货架': - for i in range(self.shelf_layer): - for j in range(self.layer_capacity): - location_name = self.name + '-' + str(i + 1) + '层' + '-' + str(j + 1) + '位置' - # 检查是否已经有同名的位置存在 - existing_location = self.search([('name', '=', location_name)]) - if not existing_location: - self.create({ - 'name': location_name, - 'location_id': self.shelf_location_id.id, - 'location_type': '货位', - 'barcode': self.generate_barcode(i, j), - 'location_status': '空闲', - }) - - def generate_barcode(self, i, j): - """ - 生成货位条码 - """ - # 这里是你生成barcode的代码 - # area_type_barcode = self.location_id.barcode - area_type_barcode = self.barcode - i_str = str(i + 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 + record.location_status = '空闲' class Sf_stock_move_line(models.Model): diff --git a/sf_warehouse/security/ir.model.access.csv b/sf_warehouse/security/ir.model.access.csv index f66fbbd6..1fa8570f 100644 --- a/sf_warehouse/security/ir.model.access.csv +++ b/sf_warehouse/security/ir.model.access.csv @@ -1,7 +1,9 @@ id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink -access_sf_shelf_location,sf.shelf.location,model_sf_shelf_location,sf_warehouse.group_sf_stock_user,1,0,0,0 -access_sf_shelf_location,sf.shelf.location,model_sf_shelf_location,sf_warehouse.group_sf_stock_manager,1,1,1,0 +access_sf_shelf_location_group_sf_stock_user,sf.shelf.location,model_sf_shelf_location,sf_warehouse.group_sf_stock_user,1,0,0,0 +access_sf_shelf_location_group_sf_stock_manager,sf.shelf.location,model_sf_shelf_location,sf_warehouse.group_sf_stock_manager,1,1,1,0 +access_sf_shelf_group_sf_stock_user,sf.shelf.group.sf.stock.user,model_sf_shelf,sf_warehouse.group_sf_stock_user,1,0,0,0 +access_sf_shelf_group_sf_stock_manager,sf.shelf.group.sf.stock.manager,model_sf_shelf,sf_warehouse.group_sf_stock_manager,1,1,1,0 access_procurement_group,procurement.group,stock.model_procurement_group,base.group_user,1,1,1,0 access_stock_warehouse_manager,stock.warehouse.manager,stock.model_stock_warehouse,sf_warehouse.group_sf_stock_user,1,1,1,0 diff --git a/sf_warehouse/views/change_stock_move_views.xml b/sf_warehouse/views/change_stock_move_views.xml index 40294a20..e7d63d67 100644 --- a/sf_warehouse/views/change_stock_move_views.xml +++ b/sf_warehouse/views/change_stock_move_views.xml @@ -11,7 +11,6 @@ diff --git a/sf_warehouse/views/shelf_location.xml b/sf_warehouse/views/shelf_location.xml index ad72f2c3..ef5747e2 100644 --- a/sf_warehouse/views/shelf_location.xml +++ b/sf_warehouse/views/shelf_location.xml @@ -1,14 +1,77 @@ + + + Sf Shelf + sf.shelf + + +
+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + + Sf Shelf tree + sf.shelf + + + + + + + + + + + + 货架 + ir.actions.act_window + sf.shelf + tree,form + + + + + + + Shelf Location tree sf.shelf.location - - - + + + @@ -56,20 +119,10 @@
-
@@ -91,31 +144,13 @@
- - - - - - - - - - - - - - - - - - + + + + + + +
@@ -134,13 +169,13 @@ #{record.location_status.raw_value == '空闲' ? 'kanban_color_1' : ''} #{record.location_status.raw_value == '占用' ? 'kanban_color_2' : ''} #{record.location_status.raw_value == '禁用' ? 'kanban_color_3' : ''}"> - +
- +
@@ -151,31 +186,31 @@
- - - - - - - - - - - - - - - - - - - - - - - - - + + + + + + + + + + + + + + + + + + + + + + + + + @@ -186,10 +221,12 @@ shelf.location.search sf.shelf.location - + @@ -197,11 +234,11 @@ - 货架货位 + 货位看板 ir.actions.act_window sf.shelf.location kanban,form - [('location_type', '=', '货位'),('check_state','=','enable')] + @@ -223,7 +260,7 @@ groups="sf_warehouse.group_sf_stock_user"/> - 货架货位 + 货位 ir.actions.act_window sf.shelf.location tree,form @@ -246,8 +283,8 @@ - From 64581abeb1490683eb37e202e1f8b6520f13b221 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Tue, 20 Feb 2024 20:17:00 +0800 Subject: [PATCH 13/17] =?UTF-8?q?=E6=B5=8B=E8=AF=95=E5=BC=82=E5=B8=B8?= =?UTF-8?q?=E9=97=AE=E9=A2=98=E4=BF=AE=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/models/model.py | 8 ++++++++ sf_warehouse/views/shelf_location.xml | 3 ++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index 14db4f8d..1d1afef2 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -254,6 +254,14 @@ class SfShelf(models.Model): shelf_layer = fields.Integer(string='货架层数') layer_capacity = fields.Integer(string='层数容量') + # 是否有货位 + is_there_area = fields.Boolean(string='是否有货位', compute='_compute_is_there_area', default=False, store=True) + + @api.depends('location_ids') + def _compute_is_there_area(self): + for record in self: + record.is_there_area = bool(record.location_ids) + @api.onchange('shelf_location_id') def _onchange_shelf_location_id(self): """ diff --git a/sf_warehouse/views/shelf_location.xml b/sf_warehouse/views/shelf_location.xml index 36292205..b22ebd6e 100644 --- a/sf_warehouse/views/shelf_location.xml +++ b/sf_warehouse/views/shelf_location.xml @@ -8,7 +8,8 @@
-
From 72df0aa640fa563abc5cc1e8a8e55282d71cbdc6 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 21 Feb 2024 11:32:06 +0800 Subject: [PATCH 14/17] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=89=A9=E6=B5=81?= =?UTF-8?q?=E6=96=B9=E5=BC=8F=E5=AF=BC=E8=87=B4=E7=9A=84=E5=88=86=E9=85=8D?= =?UTF-8?q?=E5=B7=A5=E5=8E=82=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_bf_connect/controllers/controllers.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/sf_bf_connect/controllers/controllers.py b/sf_bf_connect/controllers/controllers.py index b90a1645..aa31b8b6 100644 --- a/sf_bf_connect/controllers/controllers.py +++ b/sf_bf_connect/controllers/controllers.py @@ -33,7 +33,8 @@ class Sf_Bf_Connect(http.Controller): aa = request.env['sale.order'].sudo().search([('name', '=', order_id.name)]) logging.info('get_bfm_process_or===================================:%s' % order_id.name) aa.default_code = kw['order_number'] - aa.logistics_way = kw['logistics_way'] + if kw.get('logistics_way'): + aa.logistics_way = kw['logistics_way'] logging.info('get_bfm_process_order_listaaaaaaaaaaaaaaaaaaaaaaaaaaaa================:%s' % aa.default_code) for item in bfm_process_order_list: product = request.env['product.template'].sudo().product_create(product_id, item, order_id, From 1e006b0bd736e6e11eca666c5327d3a537e7b602 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 21 Feb 2024 14:52:14 +0800 Subject: [PATCH 15/17] =?UTF-8?q?1.=E5=B7=A5=E5=8D=95=E6=96=B0=E5=A2=9Erfi?= =?UTF-8?q?d=E5=AD=97=E6=AE=B5=202.=E4=BF=AE=E6=94=B9=E4=B8=AD=E6=8E=A7?= =?UTF-8?q?=E5=AF=B9=E6=8E=A5=E7=9A=84=E5=B7=A5=E5=8D=95=E6=8E=A5=E5=8F=A3?= =?UTF-8?q?=203.=E5=BF=AB=E9=80=9F=E8=AE=A2=E5=8D=95=E6=9D=90=E6=96=99?= =?UTF-8?q?=EF=BC=8C=E5=9E=8B=E5=8F=B7=EF=BC=8C=E5=AE=A2=E6=88=B7=E4=BF=AE?= =?UTF-8?q?=E6=94=B9=E4=B8=BA=E5=8F=AF=E9=80=89=E6=8B=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_bf_connect/models/http.py | 2 ++ sf_manufacturing/controllers/controllers.py | 4 ++-- sf_manufacturing/models/mrp_workorder.py | 1 + sf_manufacturing/views/mrp_workorder_view.xml | 2 ++ sf_sale/models/quick_easy_order.py | 4 ++-- sf_sale/views/quick_easy_order_view.xml | 2 +- 6 files changed, 10 insertions(+), 5 deletions(-) diff --git a/sf_bf_connect/models/http.py b/sf_bf_connect/models/http.py index 8f546c88..ebd85439 100644 --- a/sf_bf_connect/models/http.py +++ b/sf_bf_connect/models/http.py @@ -21,6 +21,7 @@ class Http(models.AbstractModel): def _auth_method_sf_token(cls): # 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串 datas = request.httprequest.headers.environ + logging.info(datas) if 'HTTP_TOKEN' in datas: _logger.info('token:%s' % datas['HTTP_TOKEN']) # 查询密钥 @@ -40,6 +41,7 @@ class Http(models.AbstractModel): raise AuthenticationError('请求已过期') check_str = '%s%s%s' % (datas['HTTP_TOKEN'], post_time, factory_secret.sf_secret_key) check_sf_str = hashlib.sha1(check_str.encode('utf-8')).hexdigest() + _logger.info('check_str:%s' % check_sf_str) if check_sf_str != datas['HTTP_CHECKSTR']: raise AuthenticationError('数据校验不通过') else: diff --git a/sf_manufacturing/controllers/controllers.py b/sf_manufacturing/controllers/controllers.py index 42b166b1..d75fbe69 100644 --- a/sf_manufacturing/controllers/controllers.py +++ b/sf_manufacturing/controllers/controllers.py @@ -20,9 +20,9 @@ class Manufacturing_Connect(http.Controller): res = {'Succeed': True, 'Datas': []} datas = request.httprequest.data ret = json.loads(datas) - logging.info('RfidCode:%s' % ret) + logging.info('RfidCode:%s' % ret['RfidCode']) workorder = request.env['mrp.workorder'].sudo().search( - [('production_id.name', '=', 'WH/MO/00071'), ('routing_type', '=', '装夹')]) + [('rfid_code', '=', ret['RfidCode']), ('routing_type', '=', '装夹预调')]) if workorder: for item in workorder: res['Datas'].append({ diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 01687177..e4db6346 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -133,6 +133,7 @@ class ResMrpWorkOrder(models.Model): preset_program_information = fields.Char(string="预调程序信息") workpiece_delivery_ids = fields.One2many('sf.workpiece.delivery', 'workorder_id', '工件配送') is_delivery = fields.Boolean('是否配送完成', default=False) + rfid_code = fields.Char('RFID') @api.onchange('is_ok') def _onchange_inspection_user_id(self): diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index e825ef48..78313ad2 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -176,6 +176,8 @@ attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> +
diff --git a/sf_sale/models/quick_easy_order.py b/sf_sale/models/quick_easy_order.py index 7e6b8c78..ed52d9de 100644 --- a/sf_sale/models/quick_easy_order.py +++ b/sf_sale/models/quick_easy_order.py @@ -36,8 +36,8 @@ class QuickEasyOrder(models.Model): ('0.03', '±0.03mm'), ('0.02', '±0.02mm'), ('0.01', '±0.01mm')], string='加工精度', default='0.10') - material_id = fields.Many2one('sf.production.materials', '材料', compute='_compute_material_model', store=True) - material_model_id = fields.Many2one('sf.materials.model', '型号', compute='_compute_material_model', store=True) + material_id = fields.Many2one('sf.production.materials', '材料') + material_model_id = fields.Many2one('sf.materials.model', '型号') # 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) diff --git a/sf_sale/views/quick_easy_order_view.xml b/sf_sale/views/quick_easy_order_view.xml index 1654b890..3300fc27 100644 --- a/sf_sale/views/quick_easy_order_view.xml +++ b/sf_sale/views/quick_easy_order_view.xml @@ -47,7 +47,7 @@ - + From b4538a3f9d740643ebe50484c4b5897de889bc90 Mon Sep 17 00:00:00 2001 From: mgw <1392924357@qq.com> Date: Wed, 21 Feb 2024 15:25:55 +0800 Subject: [PATCH 16/17] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=BA=8F=E5=88=97?= =?UTF-8?q?=E5=8F=B7=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/models/model.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index 1d1afef2..a1891c71 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -409,7 +409,7 @@ class Sf_stock_move_line(models.Model): ) # 添加数据 - qr.add_data(self.lot_id.name) + qr.add_data(record.lot_id.name) qr.make(fit=True) # 创建二维码图像 From 51b7bcac8a413b1e3f194f7988b6e317a7023a11 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 21 Feb 2024 16:24:10 +0800 Subject: [PATCH 17/17] =?UTF-8?q?1=E3=80=81=E6=96=B0=E5=A2=9E=E5=88=80?= =?UTF-8?q?=E5=85=B7=E7=BB=84=E3=80=81=E6=9C=BA=E5=BA=8A=E5=88=80=E5=85=B7?= =?UTF-8?q?=E7=BB=84=E6=8E=A5=E5=8F=A3=EF=BC=8C=E4=BF=AE=E6=94=B9=E4=B8=AD?= =?UTF-8?q?=E6=8E=A7=E7=9B=B8=E5=85=B3=E6=8E=A5=E5=8F=A3=E5=90=8D=E7=A7=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_base/__init__.py | 1 + sf_base/controllers/__init__.py | 1 + sf_base/controllers/controllers.py | 40 +++++++++++++++++++ sf_base/models/tool_base_new.py | 2 +- sf_quality/models/quality.py | 2 +- sf_tool_management/controllers/controllers.py | 31 +++++++++++++- sf_tool_management/models/base.py | 2 +- sf_tool_management/models/mrp_workorder.py | 2 +- 8 files changed, 76 insertions(+), 5 deletions(-) create mode 100644 sf_base/controllers/__init__.py create mode 100644 sf_base/controllers/controllers.py diff --git a/sf_base/__init__.py b/sf_base/__init__.py index 60182bcc..d76dba0b 100644 --- a/sf_base/__init__.py +++ b/sf_base/__init__.py @@ -1,2 +1,3 @@ from . import models from . import commons +from . import controllers diff --git a/sf_base/controllers/__init__.py b/sf_base/controllers/__init__.py new file mode 100644 index 00000000..e046e49f --- /dev/null +++ b/sf_base/controllers/__init__.py @@ -0,0 +1 @@ +from . import controllers diff --git a/sf_base/controllers/controllers.py b/sf_base/controllers/controllers.py new file mode 100644 index 00000000..71547a67 --- /dev/null +++ b/sf_base/controllers/controllers.py @@ -0,0 +1,40 @@ +# -*- coding: utf-8 -*- +import logging +import json +import base64 +from odoo import http +from odoo.http import request + + +class Manufacturing_Connect(http.Controller): + + @http.route('/AutoDeviceApi/MaintenanceToolGroups', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_maintenance_tool_groups_Info(self, **kw): + """ + 机床刀具组接口 + :param kw: + :return: + """ + logging.info('get_maintenance_tool_groups_Info:%s' % kw) + try: + datas = request.httprequest.data + ret = json.loads(datas) + ret = json.loads(ret['result']) + logging.info('DeviceId:%s' % ret) + tool_groups = request.env['sf.tool.groups'].sudo().search([]) + + res = {'Succeed': True, 'Datas': []} + if tool_groups: + for item in tool_groups: + device_id = '' + for equipment_id in item.equipment_ids: + device_id = '%s,%s' % (device_id, equipment_id.name) + res['Datas'].append({ + 'GroupName': item.name, + 'DeviceId': device_id + }) + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('get_maintenance_tool_groups_Info error:%s' % e) + return json.JSONEncoder().encode(res) diff --git a/sf_base/models/tool_base_new.py b/sf_base/models/tool_base_new.py index 6666132c..18656c96 100644 --- a/sf_base/models/tool_base_new.py +++ b/sf_base/models/tool_base_new.py @@ -256,7 +256,7 @@ class ToolGroups(models.Model): # ==========机床刀具组接口========== def _register_tool_groups(self, obj): - create_url = '/AutoDeviceApi/FeedBackOut' + create_url = '/AutoDeviceApi/MaintenanceToolGroups' sf_sync_config = self.env['res.config.settings'].get_values() token = sf_sync_config['token'] sf_secret_key = sf_sync_config['sf_secret_key'] diff --git a/sf_quality/models/quality.py b/sf_quality/models/quality.py index ace40ff9..18b24daa 100644 --- a/sf_quality/models/quality.py +++ b/sf_quality/models/quality.py @@ -11,7 +11,7 @@ class QualityCheck(models.Model): # ==========零件特采接口========== def _register_tool_groups(self): - create_url = '/AutoDeviceApi/FeedBackOut' + create_url = '/AutoDeviceApi/ModSpecial' sf_sync_config = self.env['res.config.settings'].get_values() token = sf_sync_config['token'] sf_secret_key = sf_sync_config['sf_secret_key'] diff --git a/sf_tool_management/controllers/controllers.py b/sf_tool_management/controllers/controllers.py index becf79ec..b40abb69 100644 --- a/sf_tool_management/controllers/controllers.py +++ b/sf_tool_management/controllers/controllers.py @@ -8,7 +8,7 @@ from odoo.http import request class Manufacturing_Connect(http.Controller): - @http.route('/AutoDeviceApi/FeedBackOut', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, + @http.route('/AutoDeviceApi/MachineToolLibrary', type='json', auth='sf_token', methods=['GET', 'POST'], csrf=False, cors="*") def get_equipment_tool_Info(self, **kw): """ @@ -55,3 +55,32 @@ class Manufacturing_Connect(http.Controller): res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} logging.info('get_equipment_tool_Info error:%s' % e) return json.JSONEncoder().encode(res) + + @http.route('/AutoDeviceApi/ToolGroups', type='json', auth='none', methods=['GET', 'POST'], csrf=False, + cors="*") + def get_functional_tool_groups_Info(self, **kw): + """ + 刀具组接口 + :param kw: + :return: + """ + logging.info('get_functional_tool_groups_Info:%s' % kw) + try: + datas = request.httprequest.data + ret = json.loads(datas) + ret = json.loads(ret['result']) + logging.info('DeviceId:%s' % ret) + functional_tools = request.env['sf.functional.cutting.tool.entity'].sudo().search([]) + + res = {'Succeed': True, 'Datas': []} + if functional_tools: + for item in functional_tools: + res['Datas'].append({ + 'GroupName': item.tool_groups_id.name, + 'ToolId': item.code, + 'ToolName': item.name + }) + except Exception as e: + res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} + logging.info('get_functional_tool_groups_Info error:%s' % e) + return json.JSONEncoder().encode(res) \ No newline at end of file diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 51ac861d..ab5e0649 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -180,7 +180,7 @@ class FunctionalCuttingToolEntity(models.Model): # ==========刀具组接口========== def _register_functional_tool_groups(self, obj): - create_url = '/AutoDeviceApi/FeedBackOut' + create_url = '/AutoDeviceApi/ToolGroups' sf_sync_config = self.env['res.config.settings'].get_values() token = sf_sync_config['token'] sf_secret_key = sf_sync_config['sf_secret_key'] diff --git a/sf_tool_management/models/mrp_workorder.py b/sf_tool_management/models/mrp_workorder.py index 7e424c96..90fe9393 100644 --- a/sf_tool_management/models/mrp_workorder.py +++ b/sf_tool_management/models/mrp_workorder.py @@ -11,7 +11,7 @@ class CNCprocessing(models.Model): # ==========MES装刀指令接口========== def register_cnc_processing(self, cnc_processing): - create_url = '/AutoDeviceApi/FeedBackOut' + create_url = '/AutoDeviceApi/MESToolLoadingInstruction' sf_sync_config = self.env['res.config.settings'].get_values() token = sf_sync_config['token'] sf_secret_key = sf_sync_config['sf_secret_key']