From dbd5c488f864219eaa5219338fad5c833b1ce1e4 Mon Sep 17 00:00:00 2001 From: "jinling.yang" Date: Wed, 26 Jun 2024 16:36:51 +0800 Subject: [PATCH 1/4] =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E5=88=B6=E9=80=A0?= =?UTF-8?q?=E8=AE=A2=E5=8D=95=E7=94=9F=E6=88=90=E6=97=B6=E6=B2=A1=E6=9C=89?= =?UTF-8?q?=E9=87=87=E8=B4=AD=E5=8D=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_manufacturing/models/stock.py | 56 +++++++++---------- sf_manufacturing/views/mrp_workorder_view.xml | 7 ++- sf_mrs_connect/controllers/controllers.py | 2 +- 3 files changed, 34 insertions(+), 31 deletions(-) diff --git a/sf_manufacturing/models/stock.py b/sf_manufacturing/models/stock.py index be81e110..c7ae6ecc 100644 --- a/sf_manufacturing/models/stock.py +++ b/sf_manufacturing/models/stock.py @@ -205,39 +205,17 @@ class StockRule(models.Model): productions_values) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) - self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) - productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ - ( - p.move_dest_ids.procure_method != 'make_to_order' and not - p.move_raw_ids and not p.workorder_ids)).action_confirm() + ''' 创建工单 ''' # productions._create_workorder() # - grouped_product_ids = {k: list(g) for k, g in groupby(productions, key=lambda x: x.product_id.id)} - # 初始化一个字典来存储每个product_id对应的生产订单名称列表 - product_id_to_production_names = {} - # 对于每个product_id,获取其所有生产订单的名称 - for product_id, productions in grouped_product_ids.items(): - # 为同一个product_id创建一个生产订单名称列表 - product_id_to_production_names[product_id] = [production.name for production in productions] - for production_item in productions: - if production_item.product_id.id in product_id_to_production_names: - # # 同一个产品多个制造订单对应一个编程单和模型库 - # # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递 - if not production_item.programming_no: - production_programming = self.env['mrp.production'].search( - [('product_id.id', '=', production_item.product_id.id), - ('origin', '=', production_item.origin)], - limit=1, order='id asc') - if not production_programming.programming_no: - production_item.fetchCNC( - ', '.join(product_id_to_production_names[production_item.product_id.id])) - else: - production_item.write({'programming_no': production_programming.programming_no, - 'programming_state': '编程中'}) - + self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) + productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ + ( + p.move_dest_ids.procure_method != 'make_to_order' and not + p.move_raw_ids and not p.workorder_ids)).action_confirm() for production in productions: ''' 创建制造订单时生成序列号 @@ -283,6 +261,28 @@ class StockRule(models.Model): 'product_id': production.product_id.id, 'state': 'draft', }) + grouped_product_ids = {k: list(g) for k, g in groupby(productions, key=lambda x: x.product_id.id)} + # 初始化一个字典来存储每个product_id对应的生产订单名称列表 + product_id_to_production_names = {} + # 对于每个product_id,获取其所有生产订单的名称 + for product_id, productions in grouped_product_ids.items(): + # 为同一个product_id创建一个生产订单名称列表 + product_id_to_production_names[product_id] = [production.name for production in productions] + for production_item in productions: + if production_item.product_id.id in product_id_to_production_names: + # # 同一个产品多个制造订单对应一个编程单和模型库 + # # 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递 + if not production_item.programming_no: + production_programming = self.env['mrp.production'].search( + [('product_id.id', '=', production_item.product_id.id), + ('origin', '=', production_item.origin)], + limit=1, order='id asc') + if not production_programming.programming_no: + production_item.fetchCNC( + ', '.join(product_id_to_production_names[production_item.product_id.id])) + else: + production_item.write({'programming_no': production_programming.programming_no, + 'programming_state': '编程中'}) return True diff --git a/sf_manufacturing/views/mrp_workorder_view.xml b/sf_manufacturing/views/mrp_workorder_view.xml index a2736834..790c0551 100644 --- a/sf_manufacturing/views/mrp_workorder_view.xml +++ b/sf_manufacturing/views/mrp_workorder_view.xml @@ -483,7 +483,10 @@ - + @@ -729,7 +732,7 @@ - +、 工件配送 sf.workpiece.delivery diff --git a/sf_mrs_connect/controllers/controllers.py b/sf_mrs_connect/controllers/controllers.py index ee2ef3e5..b6d4c659 100644 --- a/sf_mrs_connect/controllers/controllers.py +++ b/sf_mrs_connect/controllers/controllers.py @@ -40,7 +40,7 @@ class Sf_Mrs_Connect(http.Controller): download_state = request.env['sf.cnc.processing'].with_user( request.env.ref("base.user_admin")).download_file_tmp( ret['folder_name'], r) - if download_state == 0: + if download_state is False: res['status'] = -2 res['message'] = '编程单号为%s的CNC程序文件从FTP拉取失败' % (ret['programming_no']) return json.JSONEncoder().encode(res) From bcb60425b230181e4c707aaca838f4e0c1f66d09 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Wed, 26 Jun 2024 17:07:09 +0800 Subject: [PATCH 2/4] =?UTF-8?q?1=E3=80=81=E5=AE=8C=E6=88=90=20=E5=86=85?= =?UTF-8?q?=E9=83=A8=E8=B0=83=E6=8B=A8=E5=8D=95=E4=BC=98=E5=8C=96=E9=A1=B9?= =?UTF-8?q?=20=E9=9C=80=E6=B1=82=EF=BC=9B2=E3=80=81=E8=A7=A3=E5=86=B3=20?= =?UTF-8?q?=20=E4=B8=8D=E5=90=8C=E5=BA=8F=E5=88=97=E5=8F=B7=E8=B0=83?= =?UTF-8?q?=E6=8B=A8=E5=8D=95=E9=80=89=E6=8B=A9=E5=90=8C=E4=B8=80=E4=B8=AA?= =?UTF-8?q?=E8=B4=A7=E4=BD=8D=E5=8F=AF=E4=BB=A5=E7=A1=AE=E8=AE=A4=E6=88=90?= =?UTF-8?q?=E5=8A=9F=20bug=EF=BC=9B3=E3=80=81=E6=94=B6=E8=B4=A7=E5=85=A5?= =?UTF-8?q?=E5=BA=93=E6=97=B6=E6=89=AB=E6=8F=8F=E5=BD=95=E5=85=A5Rfid?= =?UTF-8?q?=E6=96=B9=E6=B3=95=E6=B7=BB=E5=8A=A0=E6=97=A5=E5=BF=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_warehouse/models/model.py | 30 +++++++++++++++---- .../views/change_stock_move_views.xml | 15 ++++++---- 2 files changed, 34 insertions(+), 11 deletions(-) diff --git a/sf_warehouse/models/model.py b/sf_warehouse/models/model.py index c429a5eb..ee212b2a 100644 --- a/sf_warehouse/models/model.py +++ b/sf_warehouse/models/model.py @@ -557,8 +557,10 @@ class SfStockMoveLine(models.Model): _name = 'stock.move.line' _inherit = ['stock.move.line', 'printing.utils'] + stock_lot_name = fields.Char('序列号名称', related='lot_id.name') current_location_id = fields.Many2one( - 'sf.shelf.location', string='当前货位', compute='_compute_current_location_id', store=True) + 'sf.shelf.location', string='当前货位', compute='_compute_current_location_id', store=True, readonly=False, + domain="[('product_id', '=', product_id),'|',('product_sn_id.name', '=', stock_lot_name),('product_sn_ids.lot_id.name','=',stock_lot_name)]") # 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) @@ -856,7 +858,9 @@ class SfStockMoveLine(models.Model): def compute_destination_location_id(self): for record in self: obj = self.env['sf.shelf.location'].search([('name', '=', - self.destination_location_id.name)]) + record.destination_location_id.name)]) + if obj and obj.product_id and obj.product_id != record.product_id: + raise ValidationError('目标货位【%s】已被【%s】产品占用!' % (obj.code, obj.product_id)) if record.lot_id: if record.product_id.tracking == 'serial': shelf_location_obj = self.env['sf.shelf.location'].search( @@ -869,7 +873,7 @@ class SfStockMoveLine(models.Model): if obj: obj.product_sn_id = record.lot_id.id elif record.product_id.tracking == 'lot': - self.put_shelf_location(record) + record.put_shelf_location(record) if not obj.product_id: obj.product_id = record.product_id.id else: @@ -980,15 +984,26 @@ class SfStockPicking(models.Model): # 调用入库方法进行入库刀货位 line.compute_destination_location_id() else: - # 对除刀柄之外的刀具物料进行 目标货位必填校验 + # 对除刀柄之外的刀具物料入库到刀具房进行 目标货位必填校验 if self.location_dest_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in ( '刀柄', False): raise ValidationError('请选择【%s】产品的目标货位!' % line.product_id.name) + if line.current_location_id: + # 对货位的批次产品进行出货 + line.put_shelf_location(line) + if line.current_location_id: + # 按序列号管理的产品 if line.current_location_id.product_sn_id: line.current_location_id.product_sn_id = False # line.current_location_id.location_status = '空闲' line.current_location_id.product_num = 0 + line.current_location_id.product_id = False + else: + # 对除刀柄之外的刀具物料从刀具房出库进行 当前货位必填校验 + if self.location_id.name == '刀具房' and line.product_id.cutting_tool_material_id.name not in ( + '刀柄', False): + raise ValidationError('请选择【%s】产品的当前货位!' % line.product_id.name) # 对入库作业的刀柄和托盘进行Rfid绑定校验 for move in self.move_ids: @@ -1115,6 +1130,7 @@ class CustomStockMove(models.Model): 采购入库扫码绑定Rfid码 """ for record in self: + logging.info('Rfid:%s' % barcode) if record: lot = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)]) if lot: @@ -1126,7 +1142,9 @@ class CustomStockMove(models.Model): '该Rfid【%s】已经被序列号为【%s】的【%s】物料所占用!' % (barcode, lot.name, material)) if '刀柄' in (record.product_id.cutting_tool_material_id.name or '') or '托盘' in ( record.product_id.fixture_material_id.name or ''): + logging.info('开始录入Rfid:%s' % record.move_line_nosuggest_ids) for move_line_nosuggest_id in record.move_line_nosuggest_ids: + logging.info('录入的记录%s , Rfid:%s' % (move_line_nosuggest_id, move_line_nosuggest_id.rfid)) if move_line_nosuggest_id.rfid: if move_line_nosuggest_id.rfid == barcode: if record.product_id.cutting_tool_material_id.name: @@ -1135,7 +1153,9 @@ class CustomStockMove(models.Model): raise ValidationError('该托盘的Rfid已经录入,请勿重复录入!!!') else: line_id = int(re.sub(r"\D", "", str(move_line_nosuggest_id.id))) - self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write({'rfid': barcode}) + res = self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write( + {'rfid': barcode}) + logging.info('Rfid是否录入:%s' % res) move_line_nosuggest_id.rfid = barcode break else: diff --git a/sf_warehouse/views/change_stock_move_views.xml b/sf_warehouse/views/change_stock_move_views.xml index a77b916c..29d09926 100644 --- a/sf_warehouse/views/change_stock_move_views.xml +++ b/sf_warehouse/views/change_stock_move_views.xml @@ -7,16 +7,18 @@ - + + - - - - - + + + + + @@ -55,6 +57,7 @@ + From 70ffbafac4696449a243d37296a9ba34f9cf024a Mon Sep 17 00:00:00 2001 From: hy <1298386937@qq.com> Date: Thu, 27 Jun 2024 09:57:12 +0800 Subject: [PATCH 3/4] =?UTF-8?q?=E7=94=98=E7=89=B9=E4=BF=AE=E6=94=B9?= =?UTF-8?q?=E8=83=8C=E6=99=AF=E9=A2=9C=E8=89=B2=E5=92=8C=E4=B8=8D=E5=8F=AF?= =?UTF-8?q?=E6=8B=96=E6=8B=BD=E6=A8=A1=E5=9D=97?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- web_gantt/static/src/js/gantt_row.js | 31 +++++++++++++++++++++--- web_gantt/static/src/scss/web_gantt.scss | 4 +++ 2 files changed, 31 insertions(+), 4 deletions(-) diff --git a/web_gantt/static/src/js/gantt_row.js b/web_gantt/static/src/js/gantt_row.js index 420e3ad5..fb7ffab7 100644 --- a/web_gantt/static/src/js/gantt_row.js +++ b/web_gantt/static/src/js/gantt_row.js @@ -592,8 +592,23 @@ var GanttRow = Widget.extend({ }); pill.decorations = pillDecorations; - if (self.colorField) { - pill._color = self._getColor(pill[self.colorField]); + // let isDelay = false + // if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工 + // isDelay = pill.order_deadline.isBefore(new Date()) + // } + pill.exState = '' + if (self.colorField){ + // console.log(self.colorField, self, pill, '颜色') + // pill._color = self._getColor(pill[self.colorField]); + // 设置pill背景颜色2 修改时间2024年6月25日17:09:43 + let isDelay = false + if(pill.state != 'processing' && pill.state != 'finished') { // 判断待加工 + isDelay = pill.order_deadline.isBefore(new Date()) + } + if(isDelay) { + pill.disableDragdrop = true + } + pill._color = self._getColor2(isDelay ? 'delay' : pill.state); } if (self.progressField) { @@ -613,6 +628,13 @@ var GanttRow = Widget.extend({ } return 0; }, + _getColor2 (state) { + return { + 'finished': 'ccc', + 'delay': 9, + 'processing': 13 // 绿色 + }[state] + }, /** * Get context to evaluate decoration * @@ -867,10 +889,11 @@ var GanttRow = Widget.extend({ if ($pill.hasClass('ui-draggable-dragging')) { return; } - var self = this; var pill = _.findWhere(this.pills, { id: $pill.data('id') }); - + if(pill.state == 'finished'){ // 已完成状态不能拖拽 + return; + } // DRAGGABLE if (this.options.canEdit && !pill.disableStartResize && !pill.disableStopResize && !this.isGroup) { diff --git a/web_gantt/static/src/scss/web_gantt.scss b/web_gantt/static/src/scss/web_gantt.scss index 7dbca3e3..bc48bee5 100644 --- a/web_gantt/static/src/scss/web_gantt.scss +++ b/web_gantt/static/src/scss/web_gantt.scss @@ -754,3 +754,7 @@ left: -0.5 * $o-connector-creator-bullet-diameter; } } + +.o_gantt_view .o_gantt_row_nogroup .o_gantt_pill.o_gantt_color_ccc { + background-color: #ccc; +} \ No newline at end of file From 05f2cb553d48a264634dc7119efa38ba045ce665 Mon Sep 17 00:00:00 2001 From: yuxianghui <3437689193@qq.com> Date: Thu, 27 Jun 2024 17:21:37 +0800 Subject: [PATCH 4/4] =?UTF-8?q?1=E3=80=81=E5=AE=8C=E6=88=90=20=E9=87=87?= =?UTF-8?q?=E8=B4=AD/=E9=87=87=E8=B4=AD=E6=80=BB=E7=9B=91=E5=B2=97?= =?UTF-8?q?=E4=BD=8D=E6=9D=83=E9=99=90=E5=A2=9E=E5=8A=A0=20=E9=9C=80?= =?UTF-8?q?=E6=B1=82=EF=BC=9B2=E3=80=81=E5=AE=8C=E6=88=90=20=E5=88=80?= =?UTF-8?q?=E5=85=B7=E5=87=BA=E5=85=A5=E5=BA=93=E5=88=97=E8=A1=A8=E7=BC=BA?= =?UTF-8?q?=E5=B0=91=E5=8D=95=E6=8D=AE=E8=B7=B3=E8=BD=AC=20=E9=9C=80?= =?UTF-8?q?=E6=B1=82=EF=BC=9B3=E3=80=81=E5=AE=8C=E6=88=90=20=20=E8=AE=BE?= =?UTF-8?q?=E5=A4=87=E8=AF=A6=E6=83=85=E7=9A=84=E6=9C=BA=E5=86=85=E8=A3=85?= =?UTF-8?q?=E5=88=80=E6=97=B6=E9=97=B4=E6=AF=94=E5=BD=93=E5=89=8D=E6=97=B6?= =?UTF-8?q?=E9=97=B4=E8=BF=98=E6=99=9A=20=20bug=EF=BC=9B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- sf_sale/models/sale_order.py | 5 +++++ sf_sale/security/group_security.xml | 4 ++-- sf_sale/views/purchase_order_view.xml | 7 +++++++ sf_tool_management/models/base.py | 6 ++---- sf_tool_management/models/maintenance_equipment.py | 3 ++- sf_tool_management/models/tool_material_search.py | 5 ++--- sf_tool_management/views/tool_material_search.xml | 1 + 7 files changed, 21 insertions(+), 10 deletions(-) diff --git a/sf_sale/models/sale_order.py b/sf_sale/models/sale_order.py index 6508132d..f47f8c8d 100644 --- a/sf_sale/models/sale_order.py +++ b/sf_sale/models/sale_order.py @@ -171,6 +171,11 @@ class ProductTemplate(models.Model): class RePurchaseOrder(models.Model): _inherit = 'purchase.order' + mrp_production_count = fields.Integer( + "Count of MO Source", + compute='_compute_mrp_production_count', + groups='mrp.group_mrp_user,sf_base.group_purchase,sf_base.group_purchase_director') + remark = fields.Text('备注') user_id = fields.Many2one( 'res.users', string='买家', index=True, tracking=True, diff --git a/sf_sale/security/group_security.xml b/sf_sale/security/group_security.xml index 5f23b5bb..97b6d05d 100644 --- a/sf_sale/security/group_security.xml +++ b/sf_sale/security/group_security.xml @@ -54,7 +54,7 @@ 销售经理查看自己的订单 - ['|',('user_id','=',user.id),('create_uid', '=',user.id)] + ['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)] @@ -74,7 +74,7 @@ 采购岗查看自己的订单 - ['|',('user_id','=',user.id),('create_uid', '=',user.id)] + ['|','|',('user_id','=',user.id),('user_id', '=', False),('create_uid', '=',user.id)] diff --git a/sf_sale/views/purchase_order_view.xml b/sf_sale/views/purchase_order_view.xml index 85f5b1c8..eda8e59d 100644 --- a/sf_sale/views/purchase_order_view.xml +++ b/sf_sale/views/purchase_order_view.xml @@ -79,6 +79,13 @@ sf_base.group_purchase,sf_base.group_purchase_director + + + mrp.group_mrp_user,sf_base.group_purchase,sf_base.group_purchase_director + + + {'readonly': [('state', 'in', ['purchase'])]} diff --git a/sf_tool_management/models/base.py b/sf_tool_management/models/base.py index 61156536..182141cf 100644 --- a/sf_tool_management/models/base.py +++ b/sf_tool_management/models/base.py @@ -944,13 +944,11 @@ class FunctionalToolDismantle(models.Model): functional_tool_assembly = self.functional_tool_id.functional_tool_name_id if self.scrap_boolean: # 刀柄报废 入库到Scrap - lot.create_stock_quant(location, location_dest_scrap_ids[-1], functional_tool_assembly.id, code, - functional_tool_assembly, functional_tool_assembly.tool_groups_id) + lot.create_stock_quant(location, location_dest_scrap_ids[-1], False, code, False, False) lot.tool_material_status = '报废' else: # 刀柄不报废 入库到刀具房 - lot.create_stock_quant(location, location_dest, functional_tool_assembly.id, code, - functional_tool_assembly, functional_tool_assembly.tool_groups_id) + lot.create_stock_quant(location, location_dest, False, code, False, False) lot.tool_material_status = '可用' # ==============功能刀具[报废]拆解================ diff --git a/sf_tool_management/models/maintenance_equipment.py b/sf_tool_management/models/maintenance_equipment.py index d308f1f1..48bc531f 100644 --- a/sf_tool_management/models/maintenance_equipment.py +++ b/sf_tool_management/models/maintenance_equipment.py @@ -3,6 +3,7 @@ import requests import logging from odoo import models, api, fields from odoo.exceptions import ValidationError +from datetime import datetime, timedelta from odoo.addons.sf_base.commons.common import Common @@ -101,7 +102,7 @@ class SfMaintenanceEquipment(models.Model): tool_install_time = {'Nomal': '正常', 'Warning': '报警'} equipment_tool_id.write({ 'functional_tool_name_id': functional_tool_id.id, - 'tool_install_time': time + 'tool_install_time': time - timedelta(hours=8) }) if functional_tool_id.current_location != '机内刀库': # 对功能刀具进行移动到生产线 diff --git a/sf_tool_management/models/tool_material_search.py b/sf_tool_management/models/tool_material_search.py index af8833fb..ededd64f 100644 --- a/sf_tool_management/models/tool_material_search.py +++ b/sf_tool_management/models/tool_material_search.py @@ -25,7 +25,8 @@ class ToolMaterial(models.Model): have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True) scrap_num = fields.Integer('报废数量', compute='_compute_number', store=True) - barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True) + barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True, + domain=[('tool_material_status', '!=', '未入库')]) @api.depends('product_id.stock_quant_ids.quantity') def _compute_number(self): @@ -46,8 +47,6 @@ class ToolMaterial(models.Model): record.scrap_num = scrap_num record.number = usable_num + have_been_used_num + scrap_num - - @api.model def _read_group_cutting_tool_material_id(self, categories, domain, order): cutting_tool_material_id = categories._search([], order=order, access_rights_uid=SUPERUSER_ID) diff --git a/sf_tool_management/views/tool_material_search.xml b/sf_tool_management/views/tool_material_search.xml index 8a740676..ef6209f3 100644 --- a/sf_tool_management/views/tool_material_search.xml +++ b/sf_tool_management/views/tool_material_search.xml @@ -63,6 +63,7 @@ +