diff --git a/jikimo_frontend/static/src/js/custom_form_status_indicator.js b/jikimo_frontend/static/src/js/custom_form_status_indicator.js index 100542b8..de50eddc 100644 --- a/jikimo_frontend/static/src/js/custom_form_status_indicator.js +++ b/jikimo_frontend/static/src/js/custom_form_status_indicator.js @@ -128,8 +128,7 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', { this.allColumns.forEach(_ => { if( tableRequiredList.indexOf(_.name) >= 0 ) { const dom = $(`th[data-name=${_.name}]`) - let t = dom.html() - dom.html('*' + t) + dom.addClass('addRequired') } }) } diff --git a/jikimo_frontend/static/src/scss/custom_style.scss b/jikimo_frontend/static/src/scss/custom_style.scss index f7195534..3c106665 100644 --- a/jikimo_frontend/static/src/scss/custom_style.scss +++ b/jikimo_frontend/static/src/scss/custom_style.scss @@ -478,4 +478,14 @@ div:has(.o_required_modifier) > label::before { 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%); +} \ No newline at end of file diff --git a/sf_base/models/tool_base_new.py b/sf_base/models/tool_base_new.py index e3b737f0..f2010b4a 100644 --- a/sf_base/models/tool_base_new.py +++ b/sf_base/models/tool_base_new.py @@ -316,6 +316,7 @@ class ToolInventory(models.Model): 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)') @@ -326,5 +327,9 @@ class ToolInventory(models.Model): 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) diff --git a/sf_base/views/tool_views.xml b/sf_base/views/tool_views.xml index 25d1824f..e52a6222 100644 --- a/sf_base/views/tool_views.xml +++ b/sf_base/views/tool_views.xml @@ -556,19 +556,23 @@ - - - + + + + + + - + + @@ -579,7 +583,10 @@ - + + + + diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index 89510ae0..99061895 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -8,6 +8,7 @@ from datetime import datetime, timedelta import requests import os import math +from lxml import etree from dateutil.relativedelta import relativedelta # import subprocess from odoo import api, fields, models, SUPERUSER_ID, _ @@ -115,6 +116,19 @@ class ResMrpWorkOrder(models.Model): processing_user_id = fields.Many2one('res.users', string='加工人') # 检测人 inspection_user_id = fields.Many2one('res.users', string='检测人') + # 保存名称 + save_name = fields.Char(string='检测文件保存名称', compute='_compute_save_name') + # 获取数据状态 + data_state = fields.Boolean(string='获取数据状态', default=False) + + @api.depends('production_id') + def _compute_save_name(self): + """ + 保存名称 + """ + for record in self: + record.save_name = record.production_id.name.replace('/', '_') + schedule_state = fields.Selection(related='production_id.schedule_state', store=True) # 工件装夹信息 functional_fixture_code = fields.Char(string="功能夹具编码", readonly=True) @@ -187,6 +201,149 @@ class ResMrpWorkOrder(models.Model): [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_id)]) return process_parameter_workorder + # 获取三次元检测点数据 + def get_three_check_datas(self): + factory_nick_name = 'XT' + ftp_resconfig = self.env['res.config.settings'].get_values() + ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), + ftp_resconfig['ftp_user'], + ftp_resconfig['ftp_password']) + # ftp.connect() + + local_dir_path = '/ftp/before' + os.makedirs(local_dir_path, exist_ok=True) + local_filename = self.save_name + '.xls' + local_file_path = os.path.join(local_dir_path, local_filename) + logging.info('local_file_path:%s' % local_file_path) + remote_path = '/home/ftp/ftp_root/ThreeTest/XT/Before/' + local_filename + logging.info('remote_path:%s' % remote_path) + + if not ftp.file_exists(remote_path): + raise UserError(f"文件不存在: {remote_path}") + + with open(local_file_path, 'wb') as local_file: + ftp.ftp.retrbinary('RETR ' + remote_path, local_file.write) + logging.info('下载文件成功') + # 解析本地文件 + # file_path = 'WH_MO_00099.xls' # 使用下载的实际文件路径 + parser = etree.XMLParser(recover=True) # Using recover to handle errors + tree = etree.parse(local_file_path, parser) + logging.info('tree:%s' % tree) + root = tree.getroot() + logging.info('root:%s' % root) + + # 准备一个外部字典来存储以PT为键的坐标字典 + pt_coordinates = {} + # 遍历每个工作表和行 + for worksheet in root.iterfind('.//{urn:schemas-microsoft-com:office:spreadsheet}Worksheet'): + sheet_name = worksheet.attrib.get('{urn:schemas-microsoft-com:office:spreadsheet}Name') + logging.info('sheet_name:%s' % sheet_name) + if sheet_name == "Sheet1": # 确保我们只查看包含数据的工作表 + current_pt = None + for row in worksheet.iterfind('.//{urn:schemas-microsoft-com:office:spreadsheet}Row'): + cells = list(row.iterfind('.//{urn:schemas-microsoft-com:office:spreadsheet}Cell')) + for i, cell in enumerate(cells): + data_cell = cell.find('.//{urn:schemas-microsoft-com:office:spreadsheet}Data') + if data_cell is not None and data_cell.text is not None: # 添加检查以确保data_cell.text不为空 + # 检查是否是PT标识 + logging.info(f"Data in cell: {data_cell.text}") # 输出单元格数据 + if "PT" in data_cell.text: + current_pt = data_cell.text + pt_coordinates[current_pt] = [] + elif data_cell.text in ["X", "Y", "Z"] and current_pt is not None: + # 确保当前单元格后面还有单元格存在,以获取理论值 + if i + 1 < len(cells): + next_cell = cells[i + 1] + theory_value = next_cell.find( + './/{urn:schemas-microsoft-com:office:spreadsheet}Data') + if theory_value is not None: + # 为当前PT键添加坐标数据 + pt_coordinates[current_pt].append({ + data_cell.text: float(theory_value.text) + }) + logging.info(f"PT: {current_pt} - {data_cell.text}: {theory_value.text}") + logging.info('pt_coordinates=====%s' % pt_coordinates) + # pt_coordinates:{'PT1': [{'X': 38.9221}, {'Y': -18.7304}, {'Z': 128.0783}], + # 'PT2': [{'X': 39.2456}, {'Y': -76.9169}, {'Z': 123.7541}]} + + # 检查是否存在PT1等键 + if 'PT1' in pt_coordinates and pt_coordinates['PT1']: + self.X1_axis = pt_coordinates['PT3'][0]['X'] + self.Y1_axis = pt_coordinates['PT3'][1]['Y'] + self.Z1_axis = pt_coordinates['PT3'][2]['Z'] + else: + raise UserError('PT1点未测或数据错误') + if 'PT2' in pt_coordinates and pt_coordinates['PT2']: + self.X2_axis = pt_coordinates['PT4'][0]['X'] + self.Y2_axis = pt_coordinates['PT4'][1]['Y'] + self.Z2_axis = pt_coordinates['PT4'][2]['Z'] + else: + raise UserError('PT2点未测或数据错误') + if 'PT3' in pt_coordinates and pt_coordinates['PT3']: + self.X3_axis = pt_coordinates['PT5'][0]['X'] + self.Y3_axis = pt_coordinates['PT5'][1]['Y'] + self.Z3_axis = pt_coordinates['PT5'][2]['Z'] + else: + raise UserError('PT3点未测或数据错误') + if 'PT4' in pt_coordinates and pt_coordinates['PT4']: + self.X4_axis = pt_coordinates['PT6'][0]['X'] + self.Y4_axis = pt_coordinates['PT6'][1]['Y'] + self.Z4_axis = pt_coordinates['PT6'][2]['Z'] + else: + raise UserError('PT4点未测或数据错误') + if 'PT5' in pt_coordinates and pt_coordinates['PT5']: + self.X5_axis = pt_coordinates['PT7'][0]['X'] + self.Y5_axis = pt_coordinates['PT7'][1]['Y'] + self.Z5_axis = pt_coordinates['PT7'][2]['Z'] + else: + raise UserError('PT5点未测或数据错误') + if 'PT6' in pt_coordinates and pt_coordinates['PT6']: + self.X6_axis = pt_coordinates['PT8'][0]['X'] + self.Y6_axis = pt_coordinates['PT8'][1]['Y'] + self.Z6_axis = pt_coordinates['PT8'][2]['Z'] + else: + raise UserError('PT6点未测或数据错误') + if 'PT7' in pt_coordinates and pt_coordinates['PT7']: + self.X7_axis = pt_coordinates['PT9'][0]['X'] + self.Y7_axis = pt_coordinates['PT9'][1]['Y'] + self.Z7_axis = pt_coordinates['PT9'][2]['Z'] + else: + raise UserError('PT7点未测或数据错误') + if 'PT8' in pt_coordinates and pt_coordinates['PT8']: + self.X8_axis = pt_coordinates['PT10'][0]['X'] + self.Y8_axis = pt_coordinates['PT10'][1]['Y'] + self.Z8_axis = pt_coordinates['PT10'][2]['Z'] + else: + raise UserError('PT8点未测或数据错误') + if 'PT9' in pt_coordinates and pt_coordinates['PT9']: + self.X9_axis = pt_coordinates['PT1'][0]['X'] + self.Y9_axis = pt_coordinates['PT1'][1]['Y'] + self.Z9_axis = pt_coordinates['PT1'][2]['Z'] + else: + raise UserError('PT9点未测或数据错误') + if 'PT10' in pt_coordinates and pt_coordinates['PT10']: + self.X10_axis = pt_coordinates['PT2'][0]['X'] + self.Y10_axis = pt_coordinates['PT2'][1]['Y'] + self.Z10_axis = pt_coordinates['PT2'][2]['Z'] + else: + raise UserError('PT10点未测或数据错误') + + self.data_state = True + + return True + + # ftp.download_file('three_check_datas.xls', '/home/ftpuser/three_check_datas.xls') + # ftp.close() + # data = xlrd.open_workbook('/home/ftpuser/three_check_datas.xls') + # table = data.sheets()[0] + # nrows = table.nrows + # # 点坐标列表 + # point_list = [] + # datas = [] + # for i in range(1, nrows): + # datas.append(table.row_values(i)) + # return datas + # 计算配料中心点和与x轴倾斜度方法 def getcenter(self): try: @@ -230,8 +387,9 @@ class ResMrpWorkOrder(models.Model): work.compensation_value_x = eval(self.material_center_point)[0] work.compensation_value_y = eval(self.material_center_point)[1] workorder.button_finish() - except: - raise UserError("参数计算有误") + except Exception as e: + # 重新抛出捕获到的异常信息 + raise UserError(str(e)) def button_workpiece_delivery(self): if self.routing_type == '装夹预调': diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 9a747791..8a76fe71 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -403,8 +403,11 @@
+ +
@@ -517,6 +520,7 @@ + diff --git a/sf_mrs_connect/models/ftp_operate.py b/sf_mrs_connect/models/ftp_operate.py index c8d0abb6..724f56b4 100644 --- a/sf_mrs_connect/models/ftp_operate.py +++ b/sf_mrs_connect/models/ftp_operate.py @@ -21,6 +21,16 @@ class FtpController(): except Exception: logging.info("ftp连接失败") + def file_exists(self, path): + # 检查文件是否存在于FTP服务器上 + try: + self.ftp.cwd(os.path.dirname(path)) + files = self.ftp.nlst() + return os.path.basename(path) in files + except Exception as e: + logging.error(f"Error checking file: {e}") + return False + # 下载目录下的文件 def download_file_tree(self, target_dir, serverdir): if not os.path.exists(serverdir): diff --git a/sf_mrs_connect/models/sync_common.py b/sf_mrs_connect/models/sync_common.py index 0a44f130..7f01743c 100644 --- a/sf_mrs_connect/models/sync_common.py +++ b/sf_mrs_connect/models/sync_common.py @@ -52,8 +52,6 @@ class MrStaticResourceDataSync(models.Model): logging.info("夹具型号已每日同步成功") self.env['sf.fixture.materials.basic.parameters'].sync_fixture_materials_basic_parameters_yesterday() logging.info("夹具型号基本参数已每日同步成功") - self.env['sf.functional.fixture.type'].sync_fixture_materials_basic_parameters_yesterday() - logging.info("夹具型号基本参数已每日同步成功") self.env['sf.functional.fixture.type'].sync_functional_fixture_type_yesterday() logging.info("功能夹具类型已每日同步成功") self.env['sf.cutting.tool.material'].sync_cutting_tool_material_yesterday() diff --git a/sf_sale/views/res_partner_view.xml b/sf_sale/views/res_partner_view.xml index 4b2d55d6..cc8f49fb 100644 --- a/sf_sale/views/res_partner_view.xml +++ b/sf_sale/views/res_partner_view.xml @@ -26,7 +26,7 @@ + attrs="{'readonly': [('id','!=', False)]}"/> {'required': [('phone', '=', False)],'readonly': [('id','!=', False)]} @@ -37,19 +37,19 @@ - {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} + {'readonly': [('id','!=', False)]} - {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} + {'readonly': [('id','!=', False)]} - {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} + {'readonly': [('id','!=', False)]} - {'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]} + {'readonly': [('id','!=', False)]} diff --git a/sf_tool_management/__manifest__.py b/sf_tool_management/__manifest__.py index a7750f69..fe65c05e 100644 --- a/sf_tool_management/__manifest__.py +++ b/sf_tool_management/__manifest__.py @@ -21,6 +21,7 @@ 'views/menu_view.xml', 'views/tool_material_search.xml', 'views/fixture_material_search_views.xml', + 'data/tool_data.xml', ], 'demo': [ ], diff --git a/sf_tool_management/data/tool_data.xml b/sf_tool_management/data/tool_data.xml index 714d03ee..282f8c2a 100644 --- a/sf_tool_management/data/tool_data.xml +++ b/sf_tool_management/data/tool_data.xml @@ -1,8 +1,12 @@ - - - - - + + 定时同步刀具物料、功能刀具信息到cloud + + code + model._cron_tool_datasync_all() + 1 + days + -1 + \ No newline at end of file diff --git a/sf_tool_management/models/functional_tool_enroll.py b/sf_tool_management/models/functional_tool_enroll.py index 8fb781f8..61ca4731 100644 --- a/sf_tool_management/models/functional_tool_enroll.py +++ b/sf_tool_management/models/functional_tool_enroll.py @@ -1,9 +1,10 @@ import json import base64 import requests +import logging from odoo import models, api from odoo.addons.sf_base.commons.common import Common -from odoo.exceptions import UserError +from odoo.exceptions import UserError, ValidationError def get_suitable_machining_method_names(item): @@ -30,6 +31,30 @@ def get_suitable_coolant_names(item): return suitable_coolant_names +class ToolDatasync(models.Model): + _name = 'sf.tool.datasync' + _description = '定时同步所有刀具' + + def _cron_tool_datasync_all(self): + try: + self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all() + logging.info("刀具物料序列号每日同步成功") + self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all() + logging.info("刀具物料每日同步成功") + self.env['sf.functional.cutting.tool.entity'].sudo().esync_enroll_functional_tool_entity_all() + logging.info("功能刀具列表每日同步成功") + self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all() + logging.info("功能刀具预警每日同步成功") + self.env['stock.move.line'].sudo().sync_enroll_functional_tool_move_all() + logging.info("功能刀具出入库记录每日同步成功") + self.env[ + 'sf.real.time.distribution.of.functional.tools'].sudo().sync_enroll_functional_tool_real_time_distribution_all() + logging.info("功能刀具安全库存每日同步成功") + except Exception as e: + logging.info("捕获错误信息:%s" % e) + raise ValidationError("数据错误导致同步失败,请联系管理员") + + class StockLot(models.Model): _inherit = 'stock.lot' _description = '刀具物料序列号注册' @@ -41,6 +66,18 @@ class StockLot(models.Model): headers = Common.get_headers(self, token, sf_secret_key) str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create" objs_all = self.env['stock.lot'].search([('id', '=', self.id), ('active', 'in', [True, False])]) + self._get_sync_stock_lot(objs_all, str_url, token, headers) + + def sync_enroll_tool_material_stock_all(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create" + objs_all = self.env['stock.lot'].search([('rfid', '!=', False)]) + self._get_sync_stock_lot(objs_all, str_url, token, headers) + + def _get_sync_stock_lot(self, objs_all, str_url, token, headers): tool_material_stock_list = [] if objs_all: for item in objs_all: @@ -57,7 +94,7 @@ class StockLot(models.Model): if ret.get('code') == 200: return '刀具物料序列号注册成功' else: - raise UserError("没有注册刀具物料序列号信息") + logging.info("没有注册刀具物料序列号信息") class ToolMaterial(models.Model): @@ -73,6 +110,18 @@ class ToolMaterial(models.Model): headers = Common.get_headers(self, token, sf_secret_key) str_url = sf_sync_config['sf_url'] + self.crea_url objs_all = self.search([('id', '=', self.id)]) + self._get_sync_tool_material_search(objs_all, str_url, token, headers) + + def sync_enroll_tool_material_all(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + str_url = sf_sync_config['sf_url'] + self.crea_url + objs_all = self.search([]) + self._get_sync_tool_material_search(objs_all, str_url, token, headers) + + def _get_sync_tool_material_search(self, objs_all, str_url, token, headers): tool_material_list = [] if objs_all: for item in objs_all: @@ -95,7 +144,7 @@ class ToolMaterial(models.Model): if ret.get('code') == 200: return '刀具物料注册成功' else: - raise UserError("没有注册刀具物料信息") + logging.info('没有注册刀具物料信息') @api.model_create_multi def create(self, vals_list): @@ -120,6 +169,18 @@ class FunctionalCuttingToolEntity(models.Model): headers = Common.get_headers(self, token, sf_secret_key) str_url = sf_sync_config['sf_url'] + self.crea_url objs_all = self.env['sf.functional.cutting.tool.entity'].search([('id', '=', self.id)]) + self._get_sync_functional_cutting_tool_entity(objs_all, str_url, token, headers) + + def esync_enroll_functional_tool_entity_all(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + str_url = sf_sync_config['sf_url'] + self.crea_url + objs_all = self.env['sf.functional.cutting.tool.entity'].search([]) + self._get_sync_functional_cutting_tool_entity(objs_all, str_url, token, headers) + + def _get_sync_functional_cutting_tool_entity(self, objs_all, str_url, token, headers): functional_tool_list = [] if objs_all: for item in objs_all: @@ -170,7 +231,7 @@ class FunctionalCuttingToolEntity(models.Model): if ret.get('code') == 200: return "功能刀具注册成功" else: - raise UserError("没有注册功能刀具信息") + logging.info('没有注册功能刀具信息') @api.model_create_multi def create(self, vals_list): @@ -201,6 +262,18 @@ class FunctionalToolWarning(models.Model): headers = Common.get_headers(self, token, sf_secret_key) str_url = sf_sync_config['sf_url'] + self.crea_url objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)]) + self.get_sync_functional_tool_warning(objs_all, str_url, token, headers) + + def sync_enroll_functional_tool_warning_all(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + str_url = sf_sync_config['sf_url'] + self.crea_url + objs_all = self.env['sf.functional.tool.warning'].search([]) + self.get_sync_functional_tool_warning(objs_all, str_url, token, headers) + + def get_sync_functional_tool_warning(self, objs_all, str_url, token, headers): tool_warning_list = [] if objs_all: for item in objs_all: @@ -237,7 +310,7 @@ class FunctionalToolWarning(models.Model): if ret.get('code') == 200: return "功能刀具预警注册成功" else: - raise UserError("没有注册功能刀具预警信息") + logging.info('没有注册功能刀具预警信息') @api.model_create_multi def create(self, vals_list): @@ -262,6 +335,18 @@ class StockMoveLine(models.Model): headers = Common.get_headers(self, token, sf_secret_key) str_url = sf_sync_config['sf_url'] + self.crea_url objs_all = self.env['stock.move.line'].search([('id', '=', self.id), ('functional_tool_name_id', '!=', False)]) + self.get_sync_stock_move_line(objs_all, str_url, token, headers) + + def sync_enroll_functional_tool_move_all(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + str_url = sf_sync_config['sf_url'] + self.crea_url + objs_all = self.env['stock.move.line'].search([('functional_tool_name_id', '!=', False)]) + self.get_sync_stock_move_line(objs_all, str_url, token, headers) + + def get_sync_stock_move_line(self, objs_all, str_url, token, headers): tool_stock_list = [] if objs_all: for item in objs_all: @@ -289,7 +374,7 @@ class StockMoveLine(models.Model): if ret.get('code') == 200: return "功能刀具出入库记录注册成功" else: - raise UserError("没有注册功能刀具出入库记录信息") + logging.info('没有注册功能刀具出入库记录信息') @api.model_create_multi def create(self, vals_list): @@ -314,6 +399,18 @@ class RealTimeDistributionFunctionalTools(models.Model): headers = Common.get_headers(self, token, sf_secret_key) str_url = sf_sync_config['sf_url'] + self.crea_url objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([('id', '=', self.id)]) + self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers) + + def sync_enroll_functional_tool_real_time_distribution_all(self): + sf_sync_config = self.env['res.config.settings'].get_values() + token = sf_sync_config['token'] + sf_secret_key = sf_sync_config['sf_secret_key'] + headers = Common.get_headers(self, token, sf_secret_key) + str_url = sf_sync_config['sf_url'] + self.crea_url + objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([]) + self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers) + + def get_sync_real_time_distribution_functional_tools(self, objs_all, str_url, token, headers): tool_distribution_list = [] if objs_all: for item in objs_all: @@ -353,7 +450,7 @@ class RealTimeDistributionFunctionalTools(models.Model): if ret.get('code') == 200: return "功能刀具出入库记录注册成功" else: - raise UserError("没有注册功能刀具出入库记录信息") + logging.info('没有注册功能刀具出入库记录信息') @api.model_create_multi def create(self, vals_list): diff --git a/sf_tool_management/wizard/wizard.py b/sf_tool_management/wizard/wizard.py index 36bb310d..303c87d5 100644 --- a/sf_tool_management/wizard/wizard.py +++ b/sf_tool_management/wizard/wizard.py @@ -222,132 +222,147 @@ class FunctionalToolAssemblyOrder(models.TransientModel): image = fields.Binary('图片') # 功能刀具组装信息 - # 整体式刀具型号 + # ===============整体式刀具型号================= + integral_freight_barcode = fields.Char('整体式刀具货位') integral_code_id = fields.Many2one('stock.lot', string='整体式刀具序列号', domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'), ('tool_material_status', '=', '可用')]) + integral_product_id = fields.Many2one('product.product', string='整体式刀具名称', + compute='_compute_integral_product_id', store=True) cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号', - related='integral_code_id.product_id.cutting_tool_model_id') - integral_name = fields.Char('整体式刀具名称', related='integral_code_id.product_id.name') + related='integral_product_id.cutting_tool_model_id') integral_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='整体式刀具规格', - related='integral_code_id.product_id.specification_id') + related='integral_product_id.specification_id') sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌', - related='integral_code_id.product_id.brand_id') + related='integral_product_id.brand_id') - # 刀片型号 + @api.depends('integral_freight_barcode') + def _compute_integral_product_id(self): + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)]) + if location: + self.integral_product_id = location.product_id.id + + # ===============刀片型号==================== + blade_freight_barcode = fields.Char('刀片货位') blade_code_id = fields.Many2one('stock.lot', '刀片序列号', domain=[('product_id.cutting_tool_material_id.name', '=', '刀片'), ('tool_material_status', '=', '可用')]) + blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id', + store=True) cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号', - related='blade_code_id.product_id.cutting_tool_model_id') - blade_name = fields.Char('刀片名称', related='blade_code_id.product_id.name') + related='blade_product_id.cutting_tool_model_id') blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格', - related='blade_code_id.product_id.specification_id') - sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_code_id.product_id.brand_id') + related='blade_product_id.specification_id') + sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id') - # 刀杆型号 + @api.depends('blade_freight_barcode') + def _compute_blade_product_id(self): + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)]) + if location: + self.blade_product_id = location.product_id.id + + # ====================刀杆型号================== + bar_freight_barcode = fields.Char('刀杆货位') bar_code_id = fields.Many2one('stock.lot', '刀杆序列号', domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆'), ('tool_material_status', '=', '可用')]) + bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id', + store=True) cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号', - related='bar_code_id.product_id.cutting_tool_model_id') - bar_name = fields.Char('刀杆名称', related='bar_code_id.product_id.name') + related='bar_product_id.cutting_tool_model_id') bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格', - related='bar_code_id.product_id.specification_id') - sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_code_id.product_id.brand_id') + related='bar_product_id.specification_id') + sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id') - # 刀盘型号 + @api.depends('bar_freight_barcode') + def _compute_bar_product_id(self): + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)]) + if location: + self.bar_product_id = location.product_id.id + + # ===============刀盘型号=================== + pad_freight_barcode = fields.Char('刀盘货位') pad_code_id = fields.Many2one('stock.lot', '刀盘序列号', domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘'), ('tool_material_status', '=', '可用')]) + pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id', + store=True) cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号', - related='pad_code_id.product_id.cutting_tool_model_id') - pad_name = fields.Char('刀盘名称', related='pad_code_id.product_id.name') + related='pad_product_id.cutting_tool_model_id') pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格', - related='pad_code_id.product_id.specification_id') - sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_code_id.product_id.brand_id') + related='pad_product_id.specification_id') + sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id') - # 刀柄型号 + @api.depends('pad_freight_barcode') + def _compute_pad_product_id(self): + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.pad_freight_barcode)]) + if location: + self.pad_product_id = location.product_id.id + + # ================刀柄型号=============== handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True, domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'), ('tool_material_status', '=', '可用')]) + handle_product_id = fields.Many2one('product.product', string='刀柄名称', related='handle_code_id.product_id') cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号', related='handle_code_id.product_id.cutting_tool_model_id') - handle_name = fields.Char('刀柄名称', related='handle_code_id.product_id.name') handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格', related='handle_code_id.product_id.specification_id') sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_code_id.product_id.brand_id') - # 夹头型号 - chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', required=True, + # =================夹头型号============== + chuck_freight_barcode = fields.Char('夹头货位', required=True) + chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', domain=[('product_id.cutting_tool_material_id.name', '=', '夹头'), ('tool_material_status', '=', '可用')]) + chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id', + store=True) cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号', - related='chuck_code_id.product_id.cutting_tool_model_id') - chuck_name = fields.Char('夹头名称', related='chuck_code_id.product_id.name') + related='chuck_product_id.cutting_tool_model_id') chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格', - related='chuck_code_id.product_id.specification_id') - sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_code_id.product_id.brand_id') + related='chuck_product_id.specification_id') + sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id') + + @api.depends('chuck_freight_barcode') + def _compute_chuck_product_id(self): + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.chuck_freight_barcode)]) + if location: + self.chuck_product_id = location.product_id.id + + # ======================================== def on_barcode_scanned(self, barcode): """ - 智能工厂组装单处扫码绑定刀具物料') + 智能工厂组装单处扫码绑定刀具物料 """ for record in self: - if 'DJWL' in barcode: - lot_ids = record.env['stock.lot'].sudo().search([('name', '=', barcode)]) - if not lot_ids: - raise ValidationError('扫描的条形码数据不存在,请重新扫描!') - for lot_id in lot_ids: - if lot_id.quant_ids[-1].location_id.name == '刀具组装位置': - raise ValidationError('该刀具物料已使用,请重新扫描!!!') - elif lot_id.quant_ids[-1].location_id.name not in '刀具房': - raise ValidationError('该刀具物料未入库,请重新扫描!!!') - tool_material_name = lot_id.product_id.cutting_tool_material_id.name - if tool_material_name == '整体式刀具': - record.integral_code_id = lot_id.id - elif tool_material_name == '刀片': - record.blade_code_id = lot_id.id - elif tool_material_name == '刀杆': - record.bar_code_id = lot_id.id - elif tool_material_name == '刀盘': - record.pad_code_id = lot_id.id - elif tool_material_name == '刀柄': - record.handle_code_id = lot_id.id - record.chuck_code_id = record.get_chuck_code_id(lot_id).id or False - elif tool_material_name == '夹头': - record.chuck_code_id = lot_id.id - else: - raise ValidationError('扫描的刀具物料不存在,请重新扫描!') - else: - lot_ids = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)]) - if not lot_ids: - raise ValidationError('扫描的刀具物料不存在,请重新扫描!') + lot_ids = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)]) + if lot_ids: for lot_id in lot_ids: if lot_id.quant_ids[-1].location_id.name in '刀具房': record.handle_code_id = lot_id.id - record.chuck_code_id = record.get_chuck_code_id(lot_id).id or False elif lot_id.quant_ids[-1].location_id.name == '刀具组装位置': raise ValidationError('该刀柄已使用,请重新扫描!!!') else: raise ValidationError('该刀柄未入库,请重新扫描!!!') - - def get_chuck_code_id(self, lot_id): - # 适用夹头型号 - cutting_tool_chuck_id = lot_id.product_id.cutting_tool_chuck_id - # 适用夹头尺寸 - fit_chuck_size = lot_id.product_id.cutting_tool_fit_chuck_size - # 适用夹头产品 - chuck_product_id = self.env['product.product'].sudo().search( - [('cutting_tool_model_id', '=', cutting_tool_chuck_id.id), - ('cutting_tool_er_size_model', '=', fit_chuck_size)]) - # 适用夹头产品序列号 - chuck_product_lot_ids = self.env['stock.lot'].sudo().search( - [('product_id', '=', chuck_product_id.id), ('tool_material_status', '=', '可用')]) - for chuck_product_lot_id in chuck_product_lot_ids: - if chuck_product_lot_id.quant_ids[-1].location_id.name in '刀具房': - return chuck_product_lot_id - return False + else: + location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)]) + if location: + material_name = location.product_id.cutting_tool_material_id.name + if material_name == '整体式刀具': + record.integral_freight_barcode = barcode + elif material_name == '刀片': + record.blade_freight_barcode = barcode + elif material_name == '刀杆': + record.bar_freight_barcode = barcode + elif material_name == '刀盘': + record.pad_freight_barcode = barcode + elif material_name == '夹头': + record.chuck_freight_barcode = barcode + else: + raise ValidationError('扫描的刀具物料不存在,请重新扫描!') + else: + raise ValidationError('扫描的刀具物料不存在,请重新扫描!') @api.depends('handle_code_id') def _compute_rfid(self): @@ -437,7 +452,7 @@ class FunctionalToolAssemblyOrder(models.TransientModel): else: obj.after_assembly_functional_tool_name = '' - @api.onchange('integral_code_id') + @api.onchange('integral_freight_barcode') def _onchange_after_assembly_functional_tool_diameter(self): for obj in self: if obj.integral_code_id: @@ -573,12 +588,12 @@ class FunctionalToolAssemblyOrder(models.TransientModel): 'name': self.after_assembly_functional_tool_name, 'rfid': self.rfid, 'tool_groups_id': self.tool_groups_id.id, - 'integral_code_id': self.integral_code_id.id, - 'blade_code_id': self.blade_code_id.id, - 'bar_code_id': self.bar_code_id.id, - 'pad_code_id': self.pad_code_id.id, + 'integral_product_id': self.integral_product_id.id, + 'blade_product_id': self.blade_product_id.id, + 'bar_product_id': self.bar_product_id.id, + 'pad_product_id': self.pad_product_id.id, 'handle_code_id': self.handle_code_id.id, - 'chuck_code_id': self.chuck_code_id.id, + 'chuck_product_id': self.chuck_product_id.id, '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, @@ -613,12 +628,12 @@ class FunctionalToolAssemblyOrder(models.TransientModel): 'tool_groups_id': self.tool_groups_id.id, 'functional_tool_name_id': functional_tool_assembly_id.id, 'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id, - 'cutting_tool_integral_model_id': self.integral_code_id.product_id.id, - 'cutting_tool_blade_model_id': self.blade_code_id.product_id.id, - 'cutting_tool_cutterbar_model_id': self.bar_code_id.product_id.id, - 'cutting_tool_cutterpad_model_id': self.pad_code_id.product_id.id, - 'cutting_tool_cutterhandle_model_id': self.handle_code_id.product_id.id, - 'cutting_tool_cutterhead_model_id': self.chuck_code_id.product_id.id, + 'cutting_tool_integral_model_id': self.integral_product_id.id, + 'cutting_tool_blade_model_id': self.blade_product_id.id, + 'cutting_tool_cutterbar_model_id': self.bar_product_id.id, + 'cutting_tool_cutterpad_model_id': self.pad_product_id.id, + 'cutting_tool_cutterhandle_model_id': self.handle_product_id.id, + 'cutting_tool_cutterhead_model_id': self.chuck_product_id.id, 'functional_tool_diameter': self.after_assembly_functional_tool_diameter, 'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle, diff --git a/sf_tool_management/wizard/wizard_view.xml b/sf_tool_management/wizard/wizard_view.xml index a1b35664..912f7dcf 100644 --- a/sf_tool_management/wizard/wizard_view.xml +++ b/sf_tool_management/wizard/wizard_view.xml @@ -201,20 +201,18 @@ + attrs="{'invisible': ['|','|',('blade_freight_barcode', '!=', False),('bar_freight_barcode', '!=', False),('pad_freight_barcode', '!=', False)]}">
- + - + @@ -223,20 +221,18 @@
- +
- + - + @@ -246,20 +242,18 @@ + attrs="{'invisible': ['|',('integral_freight_barcode', '!=', False),('pad_freight_barcode', '!=', False)]}">
- + - + @@ -269,20 +263,18 @@ + attrs="{'invisible': ['|',('bar_freight_barcode', '!=', False),('bar_freight_barcode', '!=', False)]}">
- + - + @@ -304,7 +296,7 @@ - + @@ -319,14 +311,12 @@ - + - + diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index b7a8b9d7..37030471 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -21,7 +21,6 @@ class SfLocation(models.Model): name = fields.Char('Location Name', required=True, size=20) barcode = fields.Char('Barcode', copy=False, size=15) - # 仓库类别(selection:库区、库位、货位) # location_type = fields.Selection([ # ('库区', '库区'), @@ -127,7 +126,7 @@ class SfLocation(models.Model): for record in self: if record.product_sn_id: record.product_id = record.product_sn_id.product_id - record.location_status = '占用' + # record.location_status = '占用' else: record.product_id = False # record.location_status = '空闲' @@ -305,7 +304,7 @@ class SfShelf(models.Model): class ShelfLocation(models.Model): _name = 'sf.shelf.location' _description = '货位' - _order = 'create_date desc' + _order = 'id asc, create_date asc' # current_location_id = fields.Many2one('sf.shelf.location', string='当前位置') # # 目的位置 @@ -356,10 +355,20 @@ class ShelfLocation(models.Model): ('空闲', '空闲'), ('占用', '占用'), ('禁用', '禁用') - ], string='货位状态', default='空闲', readonly=True) + ], string='货位状态', default='空闲', compute='_compute_product_num', store=True) # product_id = fields.Many2one('product.template', string='产品') - product_id = fields.Many2one('product.product', string='产品', readonly=True) + product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', store=True) product_sn_id = fields.Many2one('stock.lot', string='产品序列号') + # 产品数量 + product_num = fields.Integer('数量') + + @api.depends('product_num') + def _compute_product_num(self): + for record in self: + if record.product_num > 0: + record.location_status = '占用' + elif record.product_num == 0: + record.location_status = '空闲' # 修改货位状态为禁用 def action_location_status_disable(self): @@ -376,12 +385,20 @@ class ShelfLocation(models.Model): """ for record in self: if record.product_sn_id: - record.sudo().product_id = record.product_sn_id.product_id - record.sudo().location_status = '占用' + try: + record.sudo().product_id = record.product_sn_id.product_id + # record.sudo().location_status = '占用' + record.sudo().product_num = 1 + except Exception as e: + print('eeeeeee占用', e) else: - record.product_id = False - # record.location_status = '空闲' + try: + record.sudo().product_id = False + # record.sudo().location_status = '空闲' + record.sudo().product_num = 0 + except Exception as e: + print('eeeeeee空闲', e) # 调取获取货位信息接口 def get_sf_shelf_location_info(self): @@ -418,6 +435,8 @@ class Sf_stock_move_line(models.Model): location_dest_id_value = fields.Integer(compute='_compute_location_dest_id_value', store=True) # lot_qr_code = fields.Binary(string='二维码', compute='_compute_lot_qr_code', store=True) lot_qr_code = fields.Binary(string='二维码', compute='_compute_lot_qr_code', store=True) + current_product_id = fields.Integer(compute='_compute_location_dest_id_value', store=True) + there_is_no_sn = fields.Boolean('是否有序列号', default=False) rfid = fields.Char('Rfid', readonly=True) @@ -689,6 +708,7 @@ class Sf_stock_move_line(models.Model): def _compute_location_dest_id_value(self): for record in self: record.location_dest_id_value = record.location_dest_id.id if record.location_dest_id else False + record.current_product_id = record.product_id.id if record.product_id else False destination_location_id = fields.Many2one( 'sf.shelf.location', string='目标货位') @@ -696,23 +716,31 @@ class Sf_stock_move_line(models.Model): @api.onchange('destination_location_id') def _compute_destination_location_id(self): for record in self: - shelf_location_obj = self.env['sf.shelf.location'].search( - [('product_sn_id', '=', record.lot_id.id)]) - if shelf_location_obj: - shelf_location_obj.product_sn_id = False - # obj = self.env['sf.shelf.location'].search([('location_id', '=', - # self.destination_location_id.id)]) - obj = self.env['sf.shelf.location'].search([('name', '=', - self.destination_location_id.name)]) - if obj: - obj.product_sn_id = record.lot_id.id + if record.lot_id: + shelf_location_obj = self.env['sf.shelf.location'].search( + [('product_sn_id', '=', record.lot_id.id)]) + if shelf_location_obj: + shelf_location_obj.product_sn_id = False + # obj = self.env['sf.shelf.location'].search([('location_id', '=', + # self.destination_location_id.id)]) + obj = self.env['sf.shelf.location'].search([('name', '=', + self.destination_location_id.name)]) + if obj: + obj.product_sn_id = record.lot_id.id + else: + pass else: - pass + obj = self.env['sf.shelf.location'].search([('name', '=', + self.destination_location_id.name)]) + if obj: + obj.product_sn_id = record.lot_id.id else: obj = self.env['sf.shelf.location'].search([('name', '=', self.destination_location_id.name)]) if obj: - obj.product_sn_id = record.lot_id.id + obj.product_id = record.product_id.id + # obj.location_status = '占用' + obj.product_num += record.reserved_uom_qty class SfStockPicking(models.Model): @@ -737,8 +765,10 @@ class SfStockPicking(models.Model): for line in self.move_line_ids: if line: if line.current_location_id: - line.current_location_id.product_sn_id = False - line.current_location_id.location_status = '空闲' + if line.current_location_id.product_sn_id: + line.current_location_id.product_sn_id = False + # line.current_location_id.location_status = '空闲' + line.current_location_id.product_num = 0 for move in self.move_ids: if move and move.product_id.cutting_tool_material_id.name == '刀柄' or '托盘' in ( @@ -750,19 +780,20 @@ class SfStockPicking(models.Model): self.env['stock.lot'].search([('name', '=', item.lot_name)]).write({'rfid': item.rfid}) return res - # def print_all_barcode(self): - # """ - # 打印所有编码 - # """ - # print('================') - # for record in self.move_ids_without_package: - # print('record', record) - # print('record.move_line_ids', record.move_line_ids) - # - # # record.move_line_ids.print_qr_code() - # - # print('record.move_line_ids.lot_id', record.move_line_ids.lot_id) - # print('record.move_line_ids.lot_id.name', record.move_line_ids.lot_id.name) + +# def print_all_barcode(self): +# """ +# 打印所有编码 +# """ +# print('================') +# for record in self.move_ids_without_package: +# print('record', record) +# print('record.move_line_ids', record.move_line_ids) +# +# # record.move_line_ids.print_qr_code() +# +# print('record.move_line_ids.lot_id', record.move_line_ids.lot_id) +# print('record.move_line_ids.lot_id.name', record.move_line_ids.lot_id.name) class SfProcurementGroup(models.Model): diff --git a/sf_warehouse/views/change_stock_move_views.xml b/sf_warehouse/views/change_stock_move_views.xml index 0875fa12..0f328b4e 100644 --- a/sf_warehouse/views/change_stock_move_views.xml +++ b/sf_warehouse/views/change_stock_move_views.xml @@ -10,10 +10,18 @@
- + + + + + + + + + + diff --git a/sf_warehouse/views/shelf_location.xml b/sf_warehouse/views/shelf_location.xml index 49fdf42e..9cd4446a 100644 --- a/sf_warehouse/views/shelf_location.xml +++ b/sf_warehouse/views/shelf_location.xml @@ -149,6 +149,7 @@ +