diff --git a/sf_bf_connect/models/process_status.py b/sf_bf_connect/models/process_status.py index 1bfdd356..09fecfae 100644 --- a/sf_bf_connect/models/process_status.py +++ b/sf_bf_connect/models/process_status.py @@ -36,6 +36,7 @@ class StatusChange(models.Model): # 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_confirm'方法) try: res = super(StatusChange, self).action_confirm() + logging.info('原生方法返回结果:%s' % res) # 原有方法执行后,进行额外的操作(如调用外部API) process_start_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S') config = self.env['res.config.settings'].get_values() @@ -61,6 +62,7 @@ class StatusChange(models.Model): traceback_error = traceback.format_exc() logging.error("工厂加工同步订单状态失败:%s " % traceback_error) raise UserError(e) + logging.info('最终返回值:%s' % res) return res def action_cancel(self): diff --git a/sf_bf_connect/views/view.xml b/sf_bf_connect/views/view.xml index 184d0e71..f4245343 100644 --- a/sf_bf_connect/views/view.xml +++ b/sf_bf_connect/views/view.xml @@ -58,7 +58,7 @@ - + diff --git a/sf_dlm_management/__manifest__.py b/sf_dlm_management/__manifest__.py index a5c894d4..9a94082a 100644 --- a/sf_dlm_management/__manifest__.py +++ b/sf_dlm_management/__manifest__.py @@ -9,7 +9,7 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['sf_sale', 'sf_dlm', 'sf_manufacturing'], + 'depends': ['sf_sale', 'sf_dlm', 'sf_manufacturing','jikimo_attachment_viewer'], 'data': [ 'data/stock_data.xml', 'views/product_template_management_view.xml', diff --git a/sf_hr/models/__init__.py b/sf_hr/models/__init__.py index ffe76391..9744f0cc 100644 --- a/sf_hr/models/__init__.py +++ b/sf_hr/models/__init__.py @@ -2,3 +2,4 @@ from . import hr_employee from . import res_config_setting +from . import res_users diff --git a/sf_hr/models/hr_employee.py b/sf_hr/models/hr_employee.py index e9826f29..5d37f199 100644 --- a/sf_hr/models/hr_employee.py +++ b/sf_hr/models/hr_employee.py @@ -11,6 +11,42 @@ class JkmPracticeEmployee(models.Model): we_id = fields.Char(string='企微ID', index=True) + @api.model_create_multi + def create(self, vals_list): + for val in vals_list: + if 'work_email' in val: + val["we_id"] = self._get_we_id(val.get('work_email')) + return super(JkmPracticeEmployee, self).create(vals_list) + + def write(self, vals): + if 'work_email' in vals: + vals["we_id"] = self._get_we_id(vals.get('work_email')) + return super(JkmPracticeEmployee, self).write(vals) + + @api.depends('work_contact_id', 'work_contact_id.mobile', 'work_contact_id.email') + def _compute_work_contact_details(self): + for employee in self: + if employee.work_contact_id: + employee.mobile_phone = employee.work_contact_id.mobile + employee.work_email = employee.work_contact_id.email + if employee.work_contact_id.email: + employee.we_id = self._get_we_id(employee.work_contact_id.email) + + def _get_we_id(self, work_email): + json1 = { + 'params': { + 'work_email': work_email + } + } + url = '/api/get/we_id/info' + config = self.env['res.config.settings'].get_values() + ret = requests.post((config['ims_url'] + url), json=json1, data={}) + result = ret.json()['result'] + if result['code'] == 200: + if result['we_id']: + return result['we_id'] + return None + def _employee_info_sync(self): url = '/api/get/organization' config = self.env['res.config.settings'].get_values() diff --git a/sf_hr/models/res_users.py b/sf_hr/models/res_users.py new file mode 100644 index 00000000..7ced81bc --- /dev/null +++ b/sf_hr/models/res_users.py @@ -0,0 +1,15 @@ +# -*- coding: utf-8 -*- +import random +from odoo import models, fields, api +from odoo.http import request +from odoo.exceptions import AccessDenied + +import logging + +_logger = logging.getLogger(__name__) + + +class ResUsers(models.Model): + _inherit = 'res.users' + + we_employee_id = fields.Char(string=u'企业微信账号', related='employee_id.we_id', default="") diff --git a/sf_maintenance/models/sf_maintenance_oee.py b/sf_maintenance/models/sf_maintenance_oee.py index 0889fdb5..eef42a60 100644 --- a/sf_maintenance/models/sf_maintenance_oee.py +++ b/sf_maintenance/models/sf_maintenance_oee.py @@ -62,22 +62,22 @@ class SfMaintenanceEquipmentOEE(models.Model): ("封存(报废)", "封存(报废)")], default='正常', string="机床状态", related='equipment_id.state') - online_time = fields.Char('开机时长(小时)', reaonly='True') + online_time = fields.Char('开机时长(小时)', readonly='True') - offline_time = fields.Char('关机时长(小时)', reaonly='True') - idle_nums = fields.Integer('待机次数', reaonly='True') + offline_time = fields.Char('关机时长(小时)', readonly='True') + idle_nums = fields.Integer('待机次数', readonly='True') # 待机时长 - idle_time = fields.Char('待机时长(小时)', reaonly='True') + idle_time = fields.Char('待机时长(小时)', readonly='True') # 待机率 - idle_rate = fields.Char('待机率(%)', reaonly='True') + idle_rate = fields.Char('待机率(%)', readonly='True') - work_time = fields.Char('加工时长(小时)', reaonly='True') - work_rate = fields.Char('可用率(%)', reaonly='True') - fault_time = fields.Char('故障时长(小时)', reaonly='True') - fault_rate = fields.Char('故障率(%)', reaonly='True') - fault_nums = fields.Integer('故障次数', reaonly='True') + work_time = fields.Char('加工时长(小时)', readonly='True') + work_rate = fields.Char('可用率(%)', readonly='True') + fault_time = fields.Char('故障时长(小时)', readonly='True') + fault_rate = fields.Char('故障率(%)', readonly='True') + fault_nums = fields.Integer('故障次数', readonly='True') # 设备故障日志 sf_maintenance_logs_ids = fields.One2many('sf.maintenance.logs', 'maintenance_equipment_oee_id', '设备故障日志', @@ -367,25 +367,25 @@ class SfMaintenanceEquipmentOEELog(models.Model): [("ZXJGZX", "钻铣加工中心"), ("CXJGZX", "车削加工中心"), ("FHJGZX", "复合加工中心")], default="", string="功能类型") machine_tool_picture = fields.Binary('设备图片') - type_id = fields.Many2one('sf.machine_tool.type', '品牌型号', reaonly='True') + type_id = fields.Many2one('sf.machine_tool.type', '品牌型号', readonly='True') state = fields.Selection([("加工", "加工"), ("关机", "关机"), ("待机", "待机"), ("故障", "故障"), ("检修", "检修"), ("保养", "保养")], default="", string="实时状态") - online_time = fields.Char('开机时长', reaonly='True') + online_time = fields.Char('开机时长', readonly='True') - offline_time = fields.Char('关机时长', reaonly='True') - offline_nums = fields.Integer('关机次数', reaonly='True') + offline_time = fields.Char('关机时长', readonly='True') + offline_nums = fields.Integer('关机次数', readonly='True') # 待机时长 - idle_time = fields.Char('待机时长', reaonly='True') + idle_time = fields.Char('待机时长', readonly='True') # 待机率 - idle_rate = fields.Char('待机率', reaonly='True') + idle_rate = fields.Char('待机率', readonly='True') - work_time = fields.Char('加工时长', reaonly='True') - work_rate = fields.Char('可用率', reaonly='True') - fault_time = fields.Char('故障时长', reaonly='True') - fault_rate = fields.Char('故障率', reaonly='True') - fault_nums = fields.Integer('故障次数', reaonly='True') + work_time = fields.Char('加工时长', readonly='True') + work_rate = fields.Char('可用率', readonly='True') + fault_time = fields.Char('故障时长', readonly='True') + fault_rate = fields.Char('故障率', readonly='True') + fault_nums = fields.Integer('故障次数', readonly='True') detail_ids = fields.One2many('maintenance.equipment.oee.log.detail', 'log_id', string='日志详情') diff --git a/sf_manufacturing/__manifest__.py b/sf_manufacturing/__manifest__.py index 71f4027a..5106dcb1 100644 --- a/sf_manufacturing/__manifest__.py +++ b/sf_manufacturing/__manifest__.py @@ -10,7 +10,7 @@ """, 'category': 'sf', 'website': 'https://www.sf.jikimo.com', - 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse'], + 'depends': ['sf_base', 'sf_maintenance', 'web_widget_model_viewer', 'sf_warehouse','jikimo_attachment_viewer'], 'data': [ 'data/stock_data.xml', 'data/empty_racks_data.xml', @@ -29,6 +29,7 @@ 'views/production_line_view.xml', 'views/mrp_workcenter_views.xml', 'views/mrp_workorder_view.xml', + 'views/stock_picking_view.xml', 'views/model_type_view.xml', 'views/agv_setting_views.xml', 'views/sf_maintenance_equipment.xml', diff --git a/sf_manufacturing/models/mrp_production.py b/sf_manufacturing/models/mrp_production.py index 573bb73f..571971bc 100644 --- a/sf_manufacturing/models/mrp_production.py +++ b/sf_manufacturing/models/mrp_production.py @@ -141,12 +141,12 @@ class MrpProduction(models.Model): ], string='工序状态', default='待装夹') # 零件图号 - part_number = fields.Char('零件图号', readonly=True) + part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True) # 上传零件图纸 - part_drawing = fields.Binary('零件图纸', readonly=True) + part_drawing = fields.Binary('零件图纸', related='product_id.machining_drawings', readonly=True) - quality_standard = fields.Binary('质检标准', readonly=True) + quality_standard = fields.Binary('质检标准', related='product_id.quality_standard', readonly=True) @api.depends('product_id.manual_quotation') def _compute_manual_quotation(self): @@ -806,6 +806,8 @@ class MrpProduction(models.Model): 'date_to': date_planned_end, }) # work.write({'date_planned_start': date_planned_start, 'date_planned_finished': date_planned_end}) + # 设置一个较大的结束时间,防止在设置开始时间时,结束时间小于开始时间 + work.date_planned_finished = datetime.datetime.today() + datetime.timedelta(days=100) work.date_planned_start = date_planned_start work.date_planned_finished = date_planned_end routing_workcenter = self.env['mrp.routing.workcenter'].sudo().search( diff --git a/sf_manufacturing/models/mrp_workorder.py b/sf_manufacturing/models/mrp_workorder.py index d2613b9a..37d42b42 100644 --- a/sf_manufacturing/models/mrp_workorder.py +++ b/sf_manufacturing/models/mrp_workorder.py @@ -306,6 +306,7 @@ class ResMrpWorkOrder(models.Model): is_delivery = fields.Boolean('是否配送完成', default=False) rfid_code = fields.Char('RFID码') rfid_code_old = fields.Char('RFID码(已解除)') + is_test_env = fields.Boolean('测试环境', default=False) production_line_id = fields.Many2one('sf.production.line', related='production_id.production_line_id', string='生产线', store=True, tracking=True) @@ -321,6 +322,9 @@ class ResMrpWorkOrder(models.Model): detailed_reason = fields.Text('详细原因') is_rework = fields.Boolean(string='是否返工', default=False) + def button_change_env(self): + self.is_test_env = not self.is_test_env + @api.constrains('blocked_by_workorder_ids') def _check_no_cyclic_dependencies(self): if self.production_id.state not in ['rework'] and self.state not in ['rework']: diff --git a/sf_manufacturing/models/product_template.py b/sf_manufacturing/models/product_template.py index 0b512c36..71aa05f8 100644 --- a/sf_manufacturing/models/product_template.py +++ b/sf_manufacturing/models/product_template.py @@ -141,11 +141,11 @@ class ResProductMo(models.Model): cutting_tool_coarse_medium_fine = fields.Selection(related='cutting_tool_model_id.integral_coarse_medium_fine', string='粗/中/精') # cutting_tool_model_id.integral_coarse_medium_fine # cutting_tool_run_out_accuracy_max = fields.Float('端跳精度max', digits=(6, 1)) - cutting_tool_run_out_accuracy_max = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_max', string='端跳精度max', digits=(6, 1)) + cutting_tool_run_out_accuracy_max = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_max', string='端跳精度max') # cutting_tool_model_id.integral_run_out_accuracy_max # cutting_tool_run_out_accuracy_min = fields.Float('端跳精度min', digits=(6, 1)) cutting_tool_run_out_accuracy_min = fields.Char(related='cutting_tool_model_id.integral_run_out_accuracy_min', - string='端跳精度min', digits=(6, 1)) + string='端跳精度min') # cutting_tool_model_id.integral_run_out_accuracy_min # cutting_tool_blade_tip_working_size = fields.Char('刀尖倒角度(°)', size=20) cutting_tool_blade_tip_working_size = fields.Char(related='specification_id.blade_tip_working_size', @@ -777,8 +777,6 @@ class ResProductMo(models.Model): part_number = fields.Char(string='零件图号', readonly=True) machining_drawings = fields.Binary('2D加工图纸', readonly=True) quality_standard = fields.Binary('质检标准', readonly=True) - machining_drawings_name = fields.Char('2D加工图纸名', readonly=True) - quality_standard_name = fields.Char('质检标准名', readonly=True) @api.constrains('tool_length') def _check_tool_length_size(self): @@ -840,10 +838,10 @@ class ResProductMo(models.Model): else: return self.env.ref('sf_dlm.product_uom_cubic_millimeter') - def attachment_update(self, name, res_id, res_field): + def attachment_update(self, name, res_id, res_field, mimetype): attachment_info = self.env['ir.attachment'].sudo().search( [('res_id', '=', res_id), ('res_field', '=', res_field)], limit=1) - attachment_info.write({'name': name}) + attachment_info.write({'name': name, 'mimetype': mimetype}) # 业务平台分配工厂后在智能工厂先创建销售订单再创建该产品 def product_create(self, product_id, item, order_id, order_number, i): @@ -883,8 +881,6 @@ class ResProductMo(models.Model): 'manual_quotation': item['manual_quotation'] or False, 'part_number': item.get('part_number') or '', 'active': True, - 'machining_drawings_name': item['machining_drawings_name'], - 'quality_standard_name': item['quality_standard_name'], 'machining_drawings': '' if not item['machining_drawings'] else base64.b64decode( item['machining_drawings']), 'quality_standard': '' if not item['quality_standard'] else base64.b64decode(item['quality_standard']), @@ -895,12 +891,12 @@ class ResProductMo(models.Model): vals.update({'taxes_id': [(6, 0, [int(tax_id)])]}) copy_product_id.sudo().write(vals) product_id.product_tmpl_id.active = False - if item['machining_drawings'] and item['machining_drawings_name']: + if item['machining_drawings'] and item['machining_drawings_name'] and item['machining_drawings_mimetype']: self.attachment_update(item['machining_drawings_name'], copy_product_id.product_tmpl_id.id, - 'machining_drawings') - if item['quality_standard'] and item['quality_standard_name']: + 'machining_drawings', item['machining_drawings_mimetype']) + if item['quality_standard'] and item['quality_standard_name'] and item['quality_standard_mimetype']: self.attachment_update(item['quality_standard_name'], copy_product_id.product_tmpl_id.id, - 'quality_standard') + 'quality_standard', item['quality_standard_mimetype']) return copy_product_id def _get_ids(self, param): diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index 02161b4a..fb678fd3 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -272,21 +272,6 @@ class StockRule(models.Model): workorder_duration += workorder.duration_expected sale_order = self.env['sale.order'].sudo().search([('name', '=', production.origin)]) - # 根据销售订单号查询快速订单 - quick_easy_order = self.env['quick.easy.order'].sudo().search([('sale_order_id', '=', sale_order.id)]) - if quick_easy_order: - production.write({'part_number': quick_easy_order.part_drawing_number, - 'part_drawing': quick_easy_order.machining_drawings}) - else: - production.write({'part_number': production.product_id.part_number, - 'part_drawing': production.product_id.machining_drawings, - 'quality_standard': production.product_id.quality_standard}) - if production.product_id.machining_drawings and production.product_id.machining_drawings_name: - self.attachment_update(production.product_id.machining_drawings_name, production.id, - 'part_drawing') - if production.product_id.quality_standard and production.product_id.quality_standard_name: - self.attachment_update(production.product_id.quality_standard_name, production.id, - 'quality_standard') if sale_order: # sale_order.write({'schedule_status': 'to schedule'}) self.env['sf.production.plan'].sudo().with_company(company_id).create({ @@ -563,6 +548,35 @@ class StockPicking(models.Model): _inherit = 'stock.picking' surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数") + person_of_delivery = fields.Char('收货人', compute='_compute_origin', store=True) + telephone_of_delivery = fields.Char('电话号码', compute='_compute_origin', store=True) + address_of_delivery = fields.Char('联系地址', compute='_compute_origin') + + retrospect_ref = fields.Char('追溯参考', compute='_compute_origin', store=True) + + @api.depends('origin') + def _compute_origin(self): + """ + 计算带料入库单对应销售单 + """ + for item in self: + if item.picking_type_id.sequence_code == 'DL' and item.origin: + if 'WH/IN/' in item.origin: + picking_id = self.env['stock.picking'].search([('name', '=', item.origin)]) + if picking_id and picking_id.origin: + purchase_id = self.env['purchase.order'].sudo().search([('name', '=', picking_id.origin)]) + if purchase_id and purchase_id.origin: + sale_id = self.env['sale.order'].sudo().search([('name', '=', purchase_id.origin)]) + item.person_of_delivery = sale_id.person_of_delivery + item.telephone_of_delivery = sale_id.telephone_of_delivery + item.address_of_delivery = sale_id.address_of_delivery + + bom = self.env['mrp.bom'].sudo().search([('bom_line_ids.product_id', '=', self.move_ids.product_id.id)]) + if bom: + if item.picking_type_id.sequence_code == 'DL': + item.retrospect_ref = bom.product_tmpl_id.default_code + elif item.picking_type_id.sequence_code in ['INT', 'PC']: + item.retrospect_ref = bom.product_tmpl_id.name # 设置外协出入单的名称 def _get_name_Res(self, rescode): @@ -756,6 +770,8 @@ class ReStockMove(models.Model): self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) elif self.product_id.tracking == "lot": self._put_tool_lot(self.company_id, self.product_id, self.origin) + if not self.move_line_nosuggest_ids: + self._generate_serial_numbers() return { 'name': _('Detailed Operations'), diff --git a/sf_manufacturing/security/group_security.xml b/sf_manufacturing/security/group_security.xml index fdbc3ae5..040e7b92 100644 --- a/sf_manufacturing/security/group_security.xml +++ b/sf_manufacturing/security/group_security.xml @@ -1,5 +1,9 @@ - - + + + 演示模式 + + - \ No newline at end of file + + diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index 76c7ff4d..bb06fa04 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -197,7 +197,7 @@ -