Compare commits

..

39 Commits

Author SHA1 Message Date
jinling.yang
85aa13ec0a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化报废和返工 2024-06-07 14:54:46 +08:00
马广威
8c285c0eb5 Accept Merge Request #1068: (feature/增加批量调拨功能 -> develop)
Merge Request: 库存处增加批量调拨功能

Created By: @马广威
Accepted By: @马广威
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1068
2024-06-06 15:45:51 +08:00
mgw
22e24c5ed3 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/增加批量调拨功能 2024-06-06 15:44:38 +08:00
mgw
4459ed2e81 库存处增加批量调拨功能 2024-06-06 15:44:20 +08:00
禹翔辉
52bf899a1f Accept Merge Request #1067: (feature/刀具接口调整 -> develop)
Merge Request: 1、产品的成品、制造订单、工单添加零件图号字段;

Created By: @禹翔辉
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @禹翔辉
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1067?initial=true
2024-06-06 14:41:30 +08:00
yuxianghui
002727070d 1、产品的成品、制造订单、工单添加零件图号字段; 2024-06-06 14:38:10 +08:00
jinling.yang
63ea5d67e8 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化报废和返工
# Conflicts:
#	sf_tool_management/models/base.py
2024-06-06 09:44:53 +08:00
杨金灵
81327f04de Accept Merge Request #1065: (hotfix/优化多次编程单下发 -> develop)
Merge Request: 优化多次编程单下发

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1065
2024-06-06 09:40:06 +08:00
jinling.yang
5e1f6a09d1 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化报废和返工 2024-06-06 09:37:42 +08:00
杨金灵
e8c86c6306 Accept Merge Request #1066: (hotfix/刀具预调仪 -> develop)
Merge Request: 刀具预调仪

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1066
2024-06-06 09:37:10 +08:00
jinling.yang
8937bfb5dd Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化报废和返工 2024-06-06 09:36:51 +08:00
杨金灵
fd6b579e2a Merge branch refs/heads/develop into refs/heads/hotfix/刀具预调仪 2024-06-06 09:30:50 +08:00
杨金灵
0b2b162d85 Merge branch refs/heads/develop into refs/heads/hotfix/优化多次编程单下发 2024-06-06 09:29:39 +08:00
jinling.yang
2eaec4fa58 修复编程单下发时,删除容器内tmp目录下模型编码已有的文件 2024-06-05 18:03:08 +08:00
黄焱
e306d02ff2 Accept Merge Request #1062: (feature/前端样式修改 -> develop)
Merge Request: 设置表单页面label文本不换行

Created By: @黄焱
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @黄焱
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1062
2024-06-05 17:42:54 +08:00
黄焱
09c56b2c07 设置表单页面label文本不换行 2024-06-05 17:35:07 +08:00
yuxianghui
f4926820fe 1、清除刀具物料的自动调用同步方法; 2024-06-05 17:18:18 +08:00
jinling.yang
5361fa7678 修复create_cam_work_plan方法 2024-06-05 17:14:20 +08:00
jinling.yang
edf8e1004e 修改条件 2024-06-05 17:00:17 +08:00
jinling.yang
2dc12d6a8c 修复create_cam_work_plan方法 2024-06-05 16:59:32 +08:00
jinling.yang
17e2a3ffc3 cnc程序的程序单更新 2024-06-05 16:26:34 +08:00
jinling.yang
94b718533f 注释OCC代码 2024-06-05 16:21:22 +08:00
jinling.yang
e258e43b51 优化多次编程单下发 2024-06-05 16:09:56 +08:00
杨金灵
1af160542c Accept Merge Request #1061: (feature/优化制造订单报废流程 -> develop)
Merge Request: 优化部分制造订单报废流程

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1061
2024-06-05 15:53:56 +08:00
jinling.yang
71246af16a 还原注释代码 2024-06-05 15:52:50 +08:00
yuxianghui
d2f4e5495e 1、功能刀具拆解单优化,添加对功能刀具的当前位置校验,只有在刀具房的刀具才能进行拆解;2、中控机床刀库接口优化,清除刀位已经移除的功能刀具信息; 2024-06-05 15:20:00 +08:00
yuxianghui
ba2b833aa8 1 2024-06-05 11:00:21 +08:00
yuxianghui
cf0afd6c64 1、添加刀具预调仪功能 2024-06-05 10:54:58 +08:00
杨金灵
e290760895 Accept Merge Request #1060: (hotfix/修复工件上下产线 -> develop)
Merge Request: 修复工件上下产线

Created By: @杨金灵
Reviewed By: @马广威
Approved By: @马广威 
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/1060
2024-06-05 10:13:02 +08:00
jinling.yang
8bd5841d7a 去掉重写state方法 2024-06-04 15:59:35 +08:00
jinling.yang
6fc94042ee 中控调取cnc工单时,工单不完成,加工完成时间为当前时间 2024-06-04 10:42:34 +08:00
jinling.yang
711e0d1437 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化制造订单报废流程 2024-06-03 16:09:08 +08:00
jinling.yang
ea6de0c248 Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化制造订单报废流程
# Conflicts:
#	sf_manufacturing/models/mrp_production.py
2024-06-03 15:43:57 +08:00
yuxianghui
d213a2cf54 接口调整 2024-05-31 11:14:02 +08:00
jinling.yang
a1d8b88db2 修复工单排序 2024-05-29 10:25:23 +08:00
jinling.yang
7ab954ebbc Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/优化制造订单报废流程 2024-05-29 09:30:41 +08:00
jinling.yang
fe88a416a7 制造订单合并一张编程单下发时,工件配送记录的未下发nc程序为未下发及cnc程序没有对应ftp文件路径问题 2024-05-28 17:57:27 +08:00
黄焱
6dc29fb50a Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/前端样式修改 2024-05-27 17:48:06 +08:00
jinling.yang
412bf4b9be 优化返工和报废 2024-05-24 17:00:44 +08:00
21 changed files with 468 additions and 363 deletions

View File

@@ -521,4 +521,9 @@ div:has(.o_required_modifier) > label::before {
.o_list_renderer.o_renderer { .o_list_renderer.o_renderer {
max-width: 100%; max-width: 100%;
overflow-x: auto; overflow-x: auto;
}
// 设置表单页面label文本不换行
.o_form_view .o_group .o_wrap_label .o_form_label {
white-space: nowrap;
} }

View File

@@ -67,9 +67,10 @@ class JdEclp(models.Model):
""" """
判断是否为出库单 判断是否为出库单
""" """
if self.name: for record in self:
is_check_out = self.name.split('/') if record.name:
self.check_out = is_check_out[1] is_check_out = record.name.split('/')
record.check_out = is_check_out[1]
@api.depends('carrier_tracking_ref') @api.depends('carrier_tracking_ref')
def query_bill_pdf(self): def query_bill_pdf(self):

View File

@@ -10,6 +10,7 @@
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/> <field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
<field name='is_bfm' invisible="1"/> <field name='is_bfm' invisible="1"/>
<field name='categ_type' invisible="1"/> <field name='categ_type' invisible="1"/>
<field name='part_number' attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/> <field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
<field name="upload_model_file" <field name="upload_model_file"
widget="many2many_binary" widget="many2many_binary"

View File

@@ -215,7 +215,7 @@ class Manufacturing_Connect(http.Controller):
if workorder.state != 'progress': if workorder.state != 'progress':
res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'} res = {'Succeed': False, 'ErrorCode': 202, 'Error': '该工单未开始'}
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)
workorder.button_finish() workorder.write({'date_finished': datetime.now()})
# workorder.process_state = '待解除装夹' # workorder.process_state = '待解除装夹'
# workorder.sudo().production_id.process_state = '待解除装夹' # workorder.sudo().production_id.process_state = '待解除装夹'

View File

@@ -77,6 +77,7 @@ class MrpProduction(models.Model):
part_drawing = fields.Binary('零件图纸') part_drawing = fields.Binary('零件图纸')
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
rework_production = fields.Many2one('mrp.production', string='返工的制造订单')
@api.depends( @api.depends(
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state', 'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
@@ -154,8 +155,30 @@ class MrpProduction(models.Model):
for production in self: for production in self:
production.maintenance_count = len(production.request_ids) production.maintenance_count = len(production.request_ids)
# 制造订单报废:编程单更新
def updateCNC(self):
try:
res = {'production_no': self.name, 'programming_no': self.programming_no,
'order_no': self.origin}
logging.info('res=%s:' % res)
configsettings = self.env['res.config.settings'].get_values()
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
url = '/api/intelligent_programming/update_intelligent_programmings'
config_url = configsettings['sf_url'] + url
res['token'] = configsettings['token']
ret = requests.post(config_url, json={}, data=res, headers=config_header)
ret = ret.json()
logging.info('updateCNC-ret:%s' % ret)
if ret['status'] == 1:
self.write({'work_state': '已编程'})
else:
raise UserError(ret['message'])
except Exception as e:
logging.info('updateCNC error:%s' % e)
raise UserError("更新程单失败,请联系管理员")
# cnc程序获取 # cnc程序获取
def fetchCNC(self, production_names): def fetchCNC(self, production_names, scrap_production):
cnc = self.env['mrp.production'].search([('id', '=', self.id)]) cnc = self.env['mrp.production'].search([('id', '=', self.id)])
quick_order = self.env['quick.easy.order'].search( quick_order = self.env['quick.easy.order'].search(
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])]) [('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
@@ -171,6 +194,8 @@ class MrpProduction(models.Model):
'production_no': production_names, 'production_no': production_names,
'machine_tool_code': '', 'machine_tool_code': '',
'product_name': cnc.product_id.name, 'product_name': cnc.product_id.name,
'remanufacture_type': '' if not scrap_production else scrap_production.workorder_ids.filtered(
lambda b: b.routing_type == "CNC加工").test_results,
'model_code': cnc.product_id.model_code, 'model_code': cnc.product_id.model_code,
'material_code': self.env['sf.production.materials'].search( 'material_code': self.env['sf.production.materials'].search(
[('id', '=', cnc.product_id.materials_id.id)]).materials_no, [('id', '=', cnc.product_id.materials_id.id)]).materials_no,
@@ -268,7 +293,7 @@ class MrpProduction(models.Model):
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制; # 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心; # 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
def _create_workorder3(self): def _create_workorder3(self, is_fetchcnc=False, scrap_production=False):
# 根据product_id对self进行分组 # 根据product_id对self进行分组
grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)} grouped_product_ids = {k: list(g) for k, g in groupby(self, key=lambda x: x.product_id.id)}
# 初始化一个字典来存储每个product_id对应的生产订单名称列表 # 初始化一个字典来存储每个product_id对应的生产订单名称列表
@@ -311,11 +336,16 @@ class MrpProduction(models.Model):
production_programming = self.search( production_programming = self.search(
[('product_id.id', '=', production.product_id.id), ('origin', '=', production.origin)], [('product_id.id', '=', production.product_id.id), ('origin', '=', production.origin)],
limit=1, order='id asc') limit=1, order='id asc')
if not production_programming.programming_no: if not production_programming.programming_no or (is_fetchcnc is True and scrap_production):
production.fetchCNC(', '.join(product_id_to_production_names[production.product_id.id])) # 制造订单报废/返工也需重新编程
if (is_fetchcnc is True and scrap_production) or (
is_fetchcnc is False and scrap_production):
production.fetchCNC(', '.join(product_id_to_production_names[production.product_id.id]),
scrap_production)
else: else:
production.write({'programming_no': production_programming.programming_no, production.write({'programming_no': production_programming.programming_no,
'programming_state': '已编程' if production_programming.programming_state == '已编程' else '编程中'}) 'programming_state': '编程中'})
# # 根据加工面板的面数及对应的工序模板生成工单 # # 根据加工面板的面数及对应的工序模板生成工单
i = 0 i = 0
processing_panel_len = len(production.product_id.model_processing_panel.split(',')) processing_panel_len = len(production.product_id.model_processing_panel.split(','))
@@ -527,8 +557,8 @@ class MrpProduction(models.Model):
# work.button_finish() # work.button_finish()
# 创建工单并进行排序 # 创建工单并进行排序
def _create_workorder(self): def _create_workorder(self, is_fetchcnc=False, scrap_production=False):
self._create_workorder3() self._create_workorder3(is_fetchcnc=is_fetchcnc, scrap_production=scrap_production)
self._reset_work_order_sequence() self._reset_work_order_sequence()
return True return True

View File

@@ -199,7 +199,12 @@ class ResMrpWorkOrder(models.Model):
production_line_state = fields.Selection(related='production_id.production_line_state', production_line_state = fields.Selection(related='production_id.production_line_state',
string='上/下产线', store=True) string='上/下产线', store=True)
detection_report = fields.Binary('检测报告', readonly=True) detection_report = fields.Binary('检测报告', readonly=True)
is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True) is_remanufacture = fields.Boolean(string='重新生成制造订单', default=False)
is_fetchcnc = fields.Boolean(string='重新获取NC程序', default=False)
reason = fields.Selection(
[("programming", "编程"), ("clamping", "返工"), ("cutter", "刀具"), ("operate computer", "操机"),
("technology", "工艺"), ("customer redrawing", "客户改图"), ("other", "其他"), ], string="原因")
detailed_reason = fields.Text('详细原因')
@api.onchange('rfid_code') @api.onchange('rfid_code')
def _onchange(self): def _onchange(self):
@@ -672,14 +677,14 @@ class ResMrpWorkOrder(models.Model):
""" """
重新生成制造订单或者重新生成工单 重新生成制造订单或者重新生成工单
""" """
if self.test_results == '报废': if self.test_results in ['返工', '报废']:
values = self.env['mrp.production'].create_production1_values(self.production_id) values = self.env['mrp.production'].create_production1_values(self.production_id)
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company( productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
self.production_id.company_id).create( self.production_id.company_id).create(
values) values)
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions._create_workorder() productions._create_workorder(is_fetchcnc=self.is_fetchcnc, scrap_production=self.production_id)
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
( (
p.move_dest_ids.procure_method != 'make_to_order' and p.move_dest_ids.procure_method != 'make_to_order' and
@@ -761,6 +766,7 @@ class ResMrpWorkOrder(models.Model):
sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)]) sale_order = self.env['sale.order'].sudo().search([('name', '=', productions.origin)])
if sale_order: if sale_order:
sale_order.mrp_production_ids |= productions
# sale_order.write({'schedule_status': 'to schedule'}) # sale_order.write({'schedule_status': 'to schedule'})
self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({ self.env['sf.production.plan'].sudo().with_company(self.production_id.company_id).create({
'name': productions.name, 'name': productions.name,
@@ -772,13 +778,13 @@ class ResMrpWorkOrder(models.Model):
'product_id': productions.product_id.id, 'product_id': productions.product_id.id,
'state': 'draft', 'state': 'draft',
}) })
if self.test_results == '返工': # if self.test_results == '返工':
productions = self.production_id # productions = self.production_id
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values()) # # self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values()) # # self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
productions._create_workorder2(self.processing_panel) # productions._create_workorder2(self.processing_panel)
else: # else:
self.results = '合格' # self.results = '合格'
def json_workorder_str1(self, k, production, route): def json_workorder_str1(self, k, production, route):
workorders_values_str = [0, '', { workorders_values_str = [0, '', {
@@ -803,29 +809,28 @@ class ResMrpWorkOrder(models.Model):
}] }]
return workorders_values_str return workorders_values_str
@api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state') # @api.depends('production_availability', 'blocked_by_workorder_ids', 'blocked_by_workorder_ids.state')
def _compute_state(self): # def _compute_state(self):
super(ResMrpWorkOrder, self)._compute_state() # super(ResMrpWorkOrder, self)._compute_state()
for item in self: # for item in self:
scrap_workorder = self.env['mrp.workorder'].search( # print(item.name)
[('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'), # print(item.state)
('state', '=', 'done'), ('is_remanufacture', '=', True)]) # print(item.is_remanufacture)
print(item.name) # scrap_workorder = self.env['mrp.workorder'].search(
print(item.state) # [('production_id', '=', item.production_id.id), ('routing_type', '=', 'CNC加工'),
if item.name == 'CNC加工(返工)' and item.state not in ['ready', 'progress', 'done']: # ('state', '=', 'done'), ('test_results', 'in', ['返工', '报废'])])
item.state = 'ready' # print(scrap_workorder)
if item.routing_type == '解除装夹': # # if item.routing_type == 'CNC加工' and item.state in ['done'] and item.test_results in ['返工', '报废']:
last_workorder = self.env['mrp.workorder'].search( # if item.routing_type == '解除装夹':
[('production_id', '=', item.production_id.id), ('name', '=', 'CNC加工(返工)'), # if scrap_workorder and item.state not in ['cancel']:
('state', '!=', 'done')]) # item.state = 'cancel'
if item.state != 'pending': # elif item.routing_type == '表面工艺':
if last_workorder: # if scrap_workorder:
item.state = 'pending' # stock_move = self.env['stock.move'].search(
if scrap_workorder: # [('origin', '=', item.production_id.name)])
item.state = 'cancel' # stock_move.write({'state': 'cancel'})
elif item.routing_type == '表面工艺': # item.picking_ids.write({'state': 'cancel'})
if scrap_workorder: # item.state = 'cancel'
item.state = 'cancel'
# 重写工单开始按钮方法 # 重写工单开始按钮方法
def button_start(self): def button_start(self):
@@ -982,6 +987,7 @@ class ResMrpWorkOrder(models.Model):
raise UserError( raise UserError(
'请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name) '请先在产品中配置表面工艺为%s相关的外协服务产品' % item.surface_technics_parameters_id.name)
tem_date_planned_finished = record.date_planned_finished tem_date_planned_finished = record.date_planned_finished
tem_date_finished = record.date_finished
logging.info('routing_type:%s' % record.routing_type) logging.info('routing_type:%s' % record.routing_type)
super().button_finish() super().button_finish()
logging.info('date_planned_finished:%s' % record.date_planned_finished) logging.info('date_planned_finished:%s' % record.date_planned_finished)
@@ -990,8 +996,15 @@ class ResMrpWorkOrder(models.Model):
record.write({ record.write({
'date_planned_finished': tem_date_planned_finished # 保持原值 'date_planned_finished': tem_date_planned_finished # 保持原值
}) })
if record.routing_type == 'CNC加工':
record.write({
'date_finished': tem_date_finished # 保持原值
})
if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']: if record.routing_type == 'CNC加工' and record.test_results in ['返工', '报废']:
record.recreateManufacturingOrWorkerOrder() record.production_id.action_cancel()
record.production_id.workorder_ids.write({'rfid_code': False, 'rfid_code_old': record.rfid_code})
if record.is_remanufacture is True:
record.recreateManufacturingOrWorkerOrder()
is_production_id = True is_production_id = True
for workorder in record.production_id.workorder_ids: for workorder in record.production_id.workorder_ids:
if workorder.state != 'done': if workorder.state != 'done':
@@ -1132,14 +1145,14 @@ class CNCprocessing(models.Model):
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配 # 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path): def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
logging.info('serverdir:%s' % serverdir) logging.info('serverdir:%s' % serverdir)
logging.info('cnc_processing:%s' % cnc_processing)
for root, dirs, files in os.walk(serverdir): for root, dirs, files in os.walk(serverdir):
for f in files: for f in files:
logging.info('splitext(f):%s' % os.path.splitext(f)[1])
if os.path.splitext(f)[1] == ".pdf": if os.path.splitext(f)[1] == ".pdf":
full_path = os.path.join(serverdir, root, f) full_path = os.path.join(serverdir, root, f)
if full_path is not False: cnc_processing.workorder_id.cnc_worksheet = base64.b64encode(
if not cnc_processing.workorder_id.cnc_worksheet: open(full_path, 'rb').read())
cnc_processing.workorder_id.cnc_worksheet = base64.b64encode(
open(full_path, 'rb').read())
else: else:
if f in program_path: if f in program_path:
# if cnc_processing.program_name == f.split('.')[0]: # if cnc_processing.program_name == f.split('.')[0]:

View File

@@ -7,8 +7,8 @@ import os
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.modules import get_resource_path from odoo.modules import get_resource_path
from OCC.Extend.DataExchange import read_step_file # from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file # from OCC.Extend.DataExchange import write_stl_file
class ResProductMo(models.Model): class ResProductMo(models.Model):
@@ -530,6 +530,7 @@ class ResProductMo(models.Model):
# bfm下单 # bfm下单
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True) manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
part_number = fields.Char(string='零件图号', readonly=True)
@api.constrains('tool_length') @api.constrains('tool_length')
def _check_tool_length_size(self): def _check_tool_length_size(self):
@@ -626,6 +627,7 @@ class ResProductMo(models.Model):
'model_remark': item['remark'], 'model_remark': item['remark'],
'default_code': '%s-%s' % (order_number, i), 'default_code': '%s-%s' % (order_number, i),
'manual_quotation': item['manual_quotation'] or False, 'manual_quotation': item['manual_quotation'] or False,
'part_number': item['part_number'] or '',
'active': True, 'active': True,
} }
copy_product_id.sudo().write(vals) copy_product_id.sudo().write(vals)

View File

@@ -207,7 +207,7 @@ class StockRule(models.Model):
''' '''
创建工单 创建工单
''' '''
productions._create_workorder() productions._create_workorder(is_fetchcnc=False, scrap_production=False)
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \ productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
( (
@@ -631,8 +631,8 @@ class ReStockMove(models.Model):
'reserved_uom_qty': 1.0, 'reserved_uom_qty': 1.0,
'lot_id': purchase.picking_ids.move_line_ids.lot_id.id, 'lot_id': purchase.picking_ids.move_line_ids.lot_id.id,
'company_id': self.company_id.id, 'company_id': self.company_id.id,
'workorder_id': '' if not sorted_workorders else sorted_workorders.id, # 'workorder_id': '' if not sorted_workorders else sorted_workorders.id,
'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id, # 'production_id': '' if not sorted_workorders else sorted_workorders.production_id.id,
'state': 'assigned', 'state': 'assigned',
} }

View File

@@ -87,7 +87,7 @@
<xpath expr="//field[@name='user_id']" position="after"> <xpath expr="//field[@name='user_id']" position="after">
<field name="production_line_id" readonly="1"/> <field name="production_line_id" readonly="1"/>
<field name="production_line_state" readonly="1"/> <field name="production_line_state" readonly="1"/>
<field name="part_number"/> <field name="part_number" string="成品的零件图号"/>
<field name="part_drawing"/> <field name="part_drawing"/>
</xpath> </xpath>
<xpath expr="//header//button[@name='action_cancel']" position="replace"> <xpath expr="//header//button[@name='action_cancel']" position="replace">

View File

@@ -214,7 +214,7 @@
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="functional_fixture_type_id" <field name="functional_fixture_type_id"
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/> attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
<field name="rfid_code" force_save="1" readonly="1" cache="True" <field name="rfid_code" cache="True"
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/> attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/> <field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
</group> </group>
@@ -478,6 +478,11 @@
<group> <group>
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/> <field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
<field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/> <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>
<field name="is_fetchcnc"
attrs='{"invisible":["|",("test_results","=","合格"),("is_remanufacture","=",False)]}'/>
<field name="reason"
attrs='{"required":[("test_results","!=","合格")],"invisible":[("test_results","=","合格")]}'/>
<field name="detailed_reason" attrs='{"invisible":[("test_results","=","合格")]}'/>
<field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/> <field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}' <field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
widget="pdf_viewer"/> widget="pdf_viewer"/>
@@ -573,7 +578,7 @@
<label for="material_height" string="高"/> <label for="material_height" string="高"/>
<field name="material_height" class="o_address_zip"/> <field name="material_height" class="o_address_zip"/>
</div> </div>
<field name="part_number"/> <field name="part_number" string="成品的零件图号"/>
</xpath> </xpath>
</field> </field>
</record> </record>

View File

@@ -24,12 +24,22 @@ class Sf_Mrs_Connect(http.Controller):
ret = json.loads(datas) ret = json.loads(datas)
ret = json.loads(ret['result']) ret = json.loads(ret['result'])
logging.info('下发编程单:%s' % ret) logging.info('下发编程单:%s' % ret)
is_delete_file = False
# 查询状态为进行中且类型为获取CNC加工程序的工单 # 查询状态为进行中且类型为获取CNC加工程序的工单
cnc_production = request.env['mrp.production'].with_user( cnc_production = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search([('name', '=', ret['production_order_no'].split(',')[0])]) request.env.ref("base.user_admin")).search([('name', '=', ret['production_order_no'].split(',')[0])])
cnc_program = request.env['mrp.production'].with_user( cnc_program = request.env['mrp.production'].with_user(
request.env.ref("base.user_admin")).search( request.env.ref("base.user_admin")).search(
[('programming_no', '=', cnc_production.programming_no), ('id', '!=', cnc_production.id)]) [('programming_no', '=', cnc_production.programming_no), ('id', '!=', cnc_production.id)])
if cnc_production.workorder_ids.filtered(lambda a: a.routing_type == 'CNC加工').cnc_ids:
is_delete_file = True
cnc_production.workorder_ids.filtered(
lambda a1: a1.routing_type == 'CNC加工').cnc_ids.sudo().unlink()
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(cnc_production)
if cnc_program.workorder_ids.filtered(lambda c: c.routing_type == 'CNC加工').cnc_ids:
cnc_program.workorder_ids.filtered(
lambda c1: c1.routing_type == 'CNC加工').cnc_ids.sudo().unlink()
request.env['sf.cam.work.order.program.knife.plan'].sudo().unlink_cam_plan(cnc_program)
# cnc_program = request.env['mrp.production'].with_user( # cnc_program = request.env['mrp.production'].with_user(
# request.env.ref("base.user_admin")).search([('programming_no', '=', cnc_production.programming_no)]) # request.env.ref("base.user_admin")).search([('programming_no', '=', cnc_production.programming_no)])
logging.info('制造订单号:%s' % cnc_production.name) logging.info('制造订单号:%s' % cnc_production.name)
@@ -37,6 +47,13 @@ class Sf_Mrs_Connect(http.Controller):
# if ret['glb_file']: # if ret['glb_file']:
# cnc_production.glb_file = base64.b64encode(ret['glb_file']) # cnc_production.glb_file = base64.b64encode(ret['glb_file'])
# 拉取所有加工面的程序文件 # 拉取所有加工面的程序文件
if is_delete_file is True:
program_path_tmp_r = os.path.join('/tmp', ret['folder_name'], 'return', 'R')
files_r = os.listdir(program_path_tmp_r)
if files_r:
for file_name in files_r:
file_path = os.path.join(program_path_tmp_r, file_name)
os.remove(file_path)
for r in ret['processing_panel']: for r in ret['processing_panel']:
download_state = request.env['sf.cnc.processing'].with_user( download_state = request.env['sf.cnc.processing'].with_user(
request.env.ref("base.user_admin")).download_file_tmp( request.env.ref("base.user_admin")).download_file_tmp(
@@ -64,15 +81,17 @@ class Sf_Mrs_Connect(http.Controller):
if cnc_processing: if cnc_processing:
cnc_processing_arr.append(cnc_processing._json_cnc_processing(cnc_processing)) cnc_processing_arr.append(cnc_processing._json_cnc_processing(cnc_processing))
if (cnc_program and cnc_processing_arr) or (not cnc_program and cnc_processing_arr): if (cnc_program and cnc_processing_arr) or (not cnc_program and cnc_processing_arr):
logging.info('cnc_processing_arr:%s' % cnc_processing_arr) cnc_production.workorder_ids.filtered(lambda g: g.routing_type == '装夹预调').write(
{'processing_drawing': cnc_production.workorder_ids.filtered(
lambda g1: g1.routing_type == 'CNC加工').cnc_worksheet})
if cnc_program and cnc_processing_arr: if cnc_program and cnc_processing_arr:
cnc_program.write({'programming_state': '已编程', 'work_state': '已编程'}) cnc_program.write({'programming_state': '已编程', 'work_state': '已编程'})
cnc_program.workorder_ids.filtered(lambda b1: b1.routing_type == '装夹预调').write( cnc_program.workorder_ids.filtered(lambda d: d.routing_type == '装夹预调').write(
{'processing_drawing': cnc_production.workorder_ids.filtered( {'processing_drawing': cnc_production.workorder_ids.filtered(
lambda b1: b1.routing_type == 'CNC加工').cnc_worksheet}) lambda d1: d1.routing_type == 'CNC加工').cnc_worksheet})
cnc_program.workorder_ids.filtered(lambda b: b.routing_type == 'CNC加工').write( cnc_program.workorder_ids.filtered(lambda b: b.routing_type == 'CNC加工').write(
{'cnc_ids': cnc_processing_arr, 'cnc_worksheet': cnc_production.workorder_ids.filtered( {'cnc_ids': cnc_processing_arr, 'cnc_worksheet': cnc_production.workorder_ids.filtered(
lambda b: b.routing_type == 'CNC加工').cnc_worksheet}) lambda b1: b1.routing_type == 'CNC加工').cnc_worksheet})
cnc_program |= cnc_production cnc_program |= cnc_production
if not cnc_program and cnc_processing_arr: if not cnc_program and cnc_processing_arr:
cnc_program = cnc_production cnc_program = cnc_production

View File

@@ -46,6 +46,8 @@ class FtpController():
os.makedirs(serverdir) os.makedirs(serverdir)
try: try:
logging.info("进入FTP目录 ") logging.info("进入FTP目录 ")
self.ftp.pwd()
logging.info('当前目录:%s' % self.ftp.pwd())
logging.info('目录:%s' % target_dir) logging.info('目录:%s' % target_dir)
target_dir1 = target_dir.split('/') target_dir1 = target_dir.split('/')
logging.info('目录1:%s' % target_dir1[1]) logging.info('目录1:%s' % target_dir1[1])

View File

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

View File

@@ -6,8 +6,8 @@ import os
from datetime import datetime from datetime import datetime
from stl import mesh from stl import mesh
# from OCC.Core.GProp import GProp_GProps # from OCC.Core.GProp import GProp_GProps
from OCC.Extend.DataExchange import read_step_file # from OCC.Extend.DataExchange import read_step_file
from OCC.Extend.DataExchange import write_stl_file # from OCC.Extend.DataExchange import write_stl_file
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo import models, fields, api from odoo import models, fields, api
from odoo.modules import get_resource_path from odoo.modules import get_resource_path

View File

@@ -8,6 +8,35 @@ from odoo.http import request
class Manufacturing_Connect(http.Controller): class Manufacturing_Connect(http.Controller):
@http.route('/AutoDeviceApi/ToolGroup', type='json', auth='sf_token', 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.tool.inventory'].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.functional_cutting_tool_model_id.name,
'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)
@http.route('/AutoDeviceApi/ToolInventory', type='json', auth='none', methods=['GET', 'POST'], csrf=False, @http.route('/AutoDeviceApi/ToolInventory', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
cors="*") cors="*")
def get_functional_tool_inventory_Info(self, **kw): def get_functional_tool_inventory_Info(self, **kw):
@@ -97,4 +126,4 @@ class Manufacturing_Connect(http.Controller):
except Exception as e: except Exception as e:
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e} res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
logging.info('put_tool_preset_parameter_port error:%s' % e) logging.info('put_tool_preset_parameter_port error:%s' % e)
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)

View File

@@ -311,41 +311,54 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
'applicant': None, 'applicant': None,
'sf_functional_tool_assembly_id': None}) 'sf_functional_tool_assembly_id': None})
def create_cam_work_plan(self, cnc_processing): def create_cam_work_plan(self, cnc_processing_ids):
""" """
根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划 根据传入的工单信息查询是否有需要的功能刀具如果没有则生成CAM工单程序用刀计划
""" """
status = False for cnc_processing in cnc_processing_ids:
if cnc_processing.cutting_tool_name: status = False
functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search( if cnc_processing.cutting_tool_name:
[('name', '=', cnc_processing.cutting_tool_name)]) functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
if functional_tools: [('name', '=', cnc_processing.cutting_tool_name)])
for functional_tool in functional_tools: if functional_tools:
if functional_tool.on_tool_stock_num == 0: for functional_tool in functional_tools:
if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0: if functional_tool.on_tool_stock_num == 0:
status = True if functional_tool.tool_stock_num == 0 and functional_tool.side_shelf_num == 0:
else: status = True
status = True else:
if status: status = True
knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({ if status:
'name': cnc_processing.workorder_id.production_id.name, knife_plan = self.env['sf.cam.work.order.program.knife.plan'].sudo().create({
'cam_procedure_code': cnc_processing.program_name, 'name': cnc_processing.workorder_id.production_id.name,
'filename': cnc_processing.cnc_id.name, 'cam_procedure_code': cnc_processing.program_name,
'functional_tool_name': cnc_processing.cutting_tool_name, 'filename': cnc_processing.cnc_id.name,
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no, 'functional_tool_name': cnc_processing.cutting_tool_name,
'process_type': cnc_processing.processing_type, 'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
'margin_x_y': float(cnc_processing.margin_x_y), 'process_type': cnc_processing.processing_type,
'margin_z': float(cnc_processing.margin_z), 'margin_x_y': float(cnc_processing.margin_x_y),
'finish_depth': float(cnc_processing.depth_of_processing_z), 'margin_z': float(cnc_processing.margin_z),
'extension_length': float(cnc_processing.cutting_tool_extension_length), 'finish_depth': float(cnc_processing.depth_of_processing_z),
'shank_model': cnc_processing.cutting_tool_handle_type, 'extension_length': float(cnc_processing.cutting_tool_extension_length),
'estimated_processing_time': cnc_processing.estimated_processing_time, 'shank_model': cnc_processing.cutting_tool_handle_type,
}) 'estimated_processing_time': cnc_processing.estimated_processing_time,
logging.info('CAM工单程序用刀计划创建成功') })
# 创建装刀请求 logging.info('CAM工单程序用刀计划创建成功')
knife_plan.apply_for_tooling() # 创建装刀请求
else: knife_plan.apply_for_tooling()
logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name) else:
logging.info('功能刀具【%s】满足CNC用刀需求' % cnc_processing.cutting_tool_name)
def unlink_cam_plan(self, production):
for item in production:
cam_plan_ids = self.env['sf.cam.work.order.program.knife.plan'].search([('name', '=', item.name)])
for cam_plan_id in cam_plan_ids:
assembly_id = cam_plan_id.sf_functional_tool_assembly_id
if assembly_id.assemble_status in ('0', '待组装') and not assembly_id.start_preset_bool:
logging.info('%s删除成功!!!' % assembly_id)
assembly_id.sudo().unlink()
logging.info('unlink_cam_plan成功')
cam_plan_ids.sudo().unlink()
class FunctionalToolAssembly(models.Model): class FunctionalToolAssembly(models.Model):
@@ -543,7 +556,8 @@ class FunctionalToolAssembly(models.Model):
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True) after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True)
after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model',
string='组装后功能刀具类型', readonly=True) string='组装后功能刀具类型', readonly=True)
after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)', readonly=True, digits=(10, 3)) after_assembly_functional_tool_diameter = fields.Float(string='组装后功能刀具直径(mm)', readonly=True,
digits=(10, 3))
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)', readonly=True, digits=(10, 3)) after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)', readonly=True, digits=(10, 3))
after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', readonly=True) after_assembly_new_former = fields.Selection([('0', ''), ('1', '')], string='组装后新/旧', readonly=True)
cut_time = fields.Integer(string='已切削时间(min)', readonly=True) cut_time = fields.Integer(string='已切削时间(min)', readonly=True)
@@ -557,7 +571,7 @@ class FunctionalToolAssembly(models.Model):
after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)', readonly=True) after_assembly_alarm_value = fields.Integer(string='组装后报警值(min)', readonly=True)
after_assembly_used_value = fields.Integer(string='组装后已使用值(min)', readonly=True) after_assembly_used_value = fields.Integer(string='组装后已使用值(min)', readonly=True)
after_assembly_tool_loading_length = fields.Float(string='组装后总长度(mm)', readonly=True, digits=(10, 3)) after_assembly_tool_loading_length = fields.Float(string='组装后总长度(mm)', readonly=True, digits=(10, 3))
after_assembly_handle_length = fields.Float(string='组装后刀柄长度(mm)',readonly=True, digits=(10, 3)) after_assembly_handle_length = fields.Float(string='组装后刀柄长度(mm)', readonly=True, digits=(10, 3))
after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', readonly=True, digits=(10, 3)) after_assembly_functional_tool_length = fields.Float(string='组装后伸出长(mm)', readonly=True, digits=(10, 3))
after_assembly_effective_length = fields.Float(string='组装后有效长(mm)', readonly=True) after_assembly_effective_length = fields.Float(string='组装后有效长(mm)', readonly=True)
L_D_number = fields.Float(string='L/D值(mm)', readonly=True) L_D_number = fields.Float(string='L/D值(mm)', readonly=True)
@@ -851,6 +865,10 @@ class FunctionalToolDismantle(models.Model):
logging.info('%s刀具确认开始拆解' % self.dismantle_cause) logging.info('%s刀具确认开始拆解' % self.dismantle_cause)
if self.functional_tool_id.functional_tool_status == '已拆除': if self.functional_tool_id.functional_tool_status == '已拆除':
raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle) raise ValidationError('Rfid为【%s】的功能刀具已经拆解,请勿重复操作!' % self.functional_tool_id.rfid_dismantle)
# 对拆解的功能刀具进行校验,只有在刀具房的功能刀具才能拆解
if self.functional_tool_id.tool_room_num == 0:
raise ValidationError('Rfid为【%s】的功能刀具当前位置为【%s】,不能进行拆解!' % (
self.rfid, self.functional_tool_id.current_location))
location = self.env['stock.location'].search([('name', '=', '刀具组装位置')]) location = self.env['stock.location'].search([('name', '=', '刀具组装位置')])
location_dest = self.env['stock.location'].search([('name', '=', '刀具房')]) location_dest = self.env['stock.location'].search([('name', '=', '刀具房')])
# =================刀柄是否[报废]拆解======= # =================刀柄是否[报废]拆解=======

View File

@@ -162,13 +162,7 @@ class ToolMaterial(models.Model):
except Exception as e: except Exception as e:
logging.info("刀具物料同步失败:%s" % e) logging.info("刀具物料同步失败:%s" % e)
# @api.model_create_multi
# def create(self, vals_list):
# records = super(ToolMaterial, self).create(vals_list)
# for record in records:
# if record:
# record.enroll_tool_material()
# return records
class FunctionalCuttingToolEntity(models.Model): class FunctionalCuttingToolEntity(models.Model):
@@ -256,250 +250,208 @@ class FunctionalCuttingToolEntity(models.Model):
except Exception as e: except Exception as e:
logging.info("功能刀具同步失败:%s" % e) logging.info("功能刀具同步失败:%s" % e)
# @api.model_create_multi
# def create(self, vals_list):
# records = super(FunctionalCuttingToolEntity, self).create(vals_list)
# for record in records:
# if record:
# record.enroll_functional_tool_entity()
# return records
# def write(self, vals):
# res = super().write(vals)
# if vals.get('current_location'):
# self.enroll_functional_tool_entity()
# return res
#
# class FunctionalToolWarning(models.Model): class FunctionalToolWarning(models.Model):
# _inherit = 'sf.functional.tool.warning' _inherit = 'sf.functional.tool.warning'
# _description = '功能刀具预警注册' _description = '功能刀具预警注册'
#
# crea_url = "/api/functional_tool_warning/create" crea_url = "/api/functional_tool_warning/create"
#
# # 注册同步功能刀具预警 # 注册同步功能刀具预警
# def enroll_functional_tool_warning(self): def enroll_functional_tool_warning(self):
# logging.info('调用功能刀具预警注册接口: enroll_functional_tool_warning()') logging.info('调用功能刀具预警注册接口: enroll_functional_tool_warning()')
# sf_sync_config = self.env['res.config.settings'].get_values() sf_sync_config = self.env['res.config.settings'].get_values()
# token = sf_sync_config['token'] token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key'] sf_secret_key = sf_sync_config['sf_secret_key']
# headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
# str_url = sf_sync_config['sf_url'] + self.crea_url str_url = sf_sync_config['sf_url'] + self.crea_url
# objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)]) objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)])
# self.get_sync_functional_tool_warning(objs_all, str_url, token, headers) self.get_sync_functional_tool_warning(objs_all, str_url, token, headers)
#
# def sync_enroll_functional_tool_warning_all(self): def sync_enroll_functional_tool_warning_all(self):
# logging.info('调用功能刀具预警注册接口: sync_enroll_functional_tool_warning_all()') logging.info('调用功能刀具预警注册接口: sync_enroll_functional_tool_warning_all()')
# sf_sync_config = self.env['res.config.settings'].get_values() sf_sync_config = self.env['res.config.settings'].get_values()
# token = sf_sync_config['token'] token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key'] sf_secret_key = sf_sync_config['sf_secret_key']
# headers = Common.get_headers(self, token, sf_secret_key) headers = Common.get_headers(self, token, sf_secret_key)
# str_url = sf_sync_config['sf_url'] + self.crea_url str_url = sf_sync_config['sf_url'] + self.crea_url
# objs_all = self.env['sf.functional.tool.warning'].search([]) objs_all = self.env['sf.functional.tool.warning'].search([])
# self.get_sync_functional_tool_warning(objs_all, str_url, token, headers) 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): def get_sync_functional_tool_warning(self, objs_all, str_url, token, headers):
# tool_warning_list = [] tool_warning_list = []
# try: try:
# if objs_all: if objs_all:
# for item in objs_all: for item in objs_all:
# val = { val = {
# 'id': item.id, 'id': item.id,
# 'name': item.name, 'name': item.name,
# 'code': item.code, 'code': item.code,
# 'rfid': item.rfid, 'rfid': item.rfid,
# 'tool_groups_name': item.tool_groups_id.name, 'tool_groups_name': item.tool_groups_id.name,
# 'production_line': item.production_line_id.name, 'production_line': item.production_line_id.name,
# 'machine_tool_id': item.maintenance_equipment_id.code, 'machine_tool_id': item.maintenance_equipment_id.code,
# 'machine_tool_code': item.machine_tool_code, 'machine_tool_code': item.machine_tool_code,
# 'cutter_spacing_code': item.cutter_spacing_code_id.code, 'cutter_spacing_code': item.cutter_spacing_code_id.code,
# 'functional_tool_name': item.name, 'functional_tool_name': item.name,
# 'barcode': item.barcode_id.name, 'barcode': item.barcode_id.name,
# 'mrs_cutting_tool_type_code': item.mrs_cutting_tool_type_id.code, 'mrs_cutting_tool_type_code': item.mrs_cutting_tool_type_id.code,
# 'diameter': item.diameter, 'diameter': item.diameter,
# 'knife_tip_r_angle': item.knife_tip_r_angle, 'knife_tip_r_angle': item.knife_tip_r_angle,
# 'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'), 'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'),
# 'on_board_time': item.on_board_time.strftime('%Y-%m-%d %H:%M:%S'), 'on_board_time': item.on_board_time.strftime('%Y-%m-%d %H:%M:%S'),
# 'max_lifetime_value': item.max_lifetime_value, 'max_lifetime_value': item.max_lifetime_value,
# 'alarm_value': item.alarm_value, 'alarm_value': item.alarm_value,
# 'used_value': item.used_value, 'used_value': item.used_value,
# 'functional_tool_status': item.functional_tool_status, 'functional_tool_status': item.functional_tool_status,
# 'alarm_time': item.alarm_time.strftime('%Y-%m-%d %H:%M:%S'), 'alarm_time': item.alarm_time.strftime('%Y-%m-%d %H:%M:%S'),
# 'dispose_user': item.dispose_user, 'dispose_user': item.dispose_user,
# 'dispose_time': item.dispose_time, 'dispose_time': item.dispose_time,
# 'dispose_func': item.dispose_func, 'dispose_func': item.dispose_func,
# } }
# tool_warning_list.append(val) tool_warning_list.append(val)
# kw = json.dumps(tool_warning_list, ensure_ascii=False) kw = json.dumps(tool_warning_list, ensure_ascii=False)
# r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers) r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
# ret = r.json() ret = r.json()
# if ret.get('code') == 200: if ret.get('code') == 200:
# return "功能刀具预警注册成功" return "功能刀具预警注册成功"
# else: else:
# logging.info('没有注册功能刀具预警信息') logging.info('没有注册功能刀具预警信息')
# except Exception as e: except Exception as e:
# logging.info("捕获错误信息:%s" % e) logging.info("捕获错误信息:%s" % e)
#
# @api.model_create_multi
# def create(self, vals_list): class StockMoveLine(models.Model):
# records = super(FunctionalToolWarning, self).create(vals_list) _inherit = 'stock.move.line'
# for record in records: _description = '功能刀具出入库记录注册'
# if record:
# record.enroll_functional_tool_warning() crea_url = "/api/functional_tool_move/create"
# return records
# # 注册同步功能刀具出入库记录
# def enroll_functional_tool_move(self):
# class StockMoveLine(models.Model): logging.info('调用功能刀具出入库记录注册接口: enroll_functional_tool_move()')
# _inherit = 'stock.move.line' sf_sync_config = self.env['res.config.settings'].get_values()
# _description = '功能刀具出入库记录注册' token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key']
# crea_url = "/api/functional_tool_move/create" 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)])
# def enroll_functional_tool_move(self): self.get_sync_stock_move_line(objs_all, str_url, token, headers)
# logging.info('调用功能刀具出入库记录注册接口: enroll_functional_tool_move()')
# sf_sync_config = self.env['res.config.settings'].get_values() def sync_enroll_functional_tool_move_all(self):
# token = sf_sync_config['token'] logging.info('调用功能刀具出入库记录注册接口: sync_enroll_functional_tool_move_all()')
# sf_secret_key = sf_sync_config['sf_secret_key'] sf_sync_config = self.env['res.config.settings'].get_values()
# headers = Common.get_headers(self, token, sf_secret_key) token = sf_sync_config['token']
# str_url = sf_sync_config['sf_url'] + self.crea_url sf_secret_key = sf_sync_config['sf_secret_key']
# objs_all = self.env['stock.move.line'].search([('id', '=', self.id), ('functional_tool_name_id', '!=', False)]) headers = Common.get_headers(self, token, sf_secret_key)
# self.get_sync_stock_move_line(objs_all, str_url, token, headers) str_url = sf_sync_config['sf_url'] + self.crea_url
# objs_all = self.env['stock.move.line'].search([('functional_tool_name_id', '!=', False)])
# def sync_enroll_functional_tool_move_all(self): self.get_sync_stock_move_line(objs_all, str_url, token, headers)
# logging.info('调用功能刀具出入库记录注册接口: sync_enroll_functional_tool_move_all()')
# sf_sync_config = self.env['res.config.settings'].get_values() def get_sync_stock_move_line(self, objs_all, str_url, token, headers):
# token = sf_sync_config['token'] tool_stock_list = []
# sf_secret_key = sf_sync_config['sf_secret_key'] try:
# headers = Common.get_headers(self, token, sf_secret_key) if objs_all:
# str_url = sf_sync_config['sf_url'] + self.crea_url for item in objs_all:
# objs_all = self.env['stock.move.line'].search([('functional_tool_name_id', '!=', False)]) val = {
# self.get_sync_stock_move_line(objs_all, str_url, token, headers) 'id': item.id,
# 'name': item.functional_tool_name,
# def get_sync_stock_move_line(self, objs_all, str_url, token, headers): 'code': item.code,
# tool_stock_list = [] 'rfid': item.rfid,
# try: 'tool_groups_name': item.tool_groups_id.name,
# if objs_all: 'reference': item.reference,
# for item in objs_all: 'barcode': item.lot_id.name,
# val = { 'functional_tool_type_code': item.functional_tool_type_id.code,
# 'id': item.id, 'diameter': item.diameter,
# 'name': item.functional_tool_name, 'knife_tip_r_angle': item.knife_tip_r_angle,
# 'code': item.code, 'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'),
# 'rfid': item.rfid, 'location_id': item.location_id.name,
# 'tool_groups_name': item.tool_groups_id.name, 'location_dest_name': item.location_dest_id.name,
# 'reference': item.reference, 'date': item.date.strftime('%Y-%m-%d %H:%M:%S'),
# 'barcode': item.lot_id.name, 'qty_done': item.qty_done,
# 'functional_tool_type_code': item.functional_tool_type_id.code, }
# 'diameter': item.diameter, tool_stock_list.append(val)
# 'knife_tip_r_angle': item.knife_tip_r_angle, kw = json.dumps(tool_stock_list, ensure_ascii=False)
# 'install_tool_time': item.install_tool_time.strftime('%Y-%m-%d %H:%M:%S'), r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
# 'location_id': item.location_id.name, ret = r.json()
# 'location_dest_name': item.location_dest_id.name, if ret.get('code') == 200:
# 'date': item.date.strftime('%Y-%m-%d %H:%M:%S'), return "功能刀具出入库记录注册成功"
# 'qty_done': item.qty_done, else:
# } logging.info('没有注册功能刀具出入库记录信息')
# tool_stock_list.append(val) except Exception as e:
# kw = json.dumps(tool_stock_list, ensure_ascii=False) logging.info("捕获错误信息:%s" % e)
# r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
# ret = r.json()
# if ret.get('code') == 200: class RealTimeDistributionFunctionalTools(models.Model):
# return "功能刀具出入库记录注册成功" _inherit = 'sf.real.time.distribution.of.functional.tools'
# else: _description = '功能刀具安全库存注册'
# logging.info('没有注册功能刀具出入库记录信息')
# except Exception as e: crea_url = "/api/functional_tool_distribution/create"
# logging.info("捕获错误信息:%s" % e)
# # 注册同步功能刀具预警
# @api.model_create_multi def enroll_functional_tool_real_time_distribution(self):
# def create(self, vals_list): logging.info('调用功能刀具安全库存注册接口: enroll_functional_tool_real_time_distribution()')
# records = super(StockMoveLine, self).create(vals_list) sf_sync_config = self.env['res.config.settings'].get_values()
# for record in records: token = sf_sync_config['token']
# if record.functional_tool_name_id: sf_secret_key = sf_sync_config['sf_secret_key']
# record.enroll_functional_tool_move() headers = Common.get_headers(self, token, sf_secret_key)
# return records 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)
# class RealTimeDistributionFunctionalTools(models.Model):
# _inherit = 'sf.real.time.distribution.of.functional.tools' def sync_enroll_functional_tool_real_time_distribution_all(self):
# _description = '功能刀具安全库存注册' logging.info('调用功能刀具安全库存注册接口: sync_enroll_functional_tool_real_time_distribution_all()')
# sf_sync_config = self.env['res.config.settings'].get_values()
# crea_url = "/api/functional_tool_distribution/create" token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key']
# # 注册同步功能刀具预警 headers = Common.get_headers(self, token, sf_secret_key)
# def enroll_functional_tool_real_time_distribution(self): str_url = sf_sync_config['sf_url'] + self.crea_url
# logging.info('调用功能刀具安全库存注册接口: enroll_functional_tool_real_time_distribution()') objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([])
# sf_sync_config = self.env['res.config.settings'].get_values() self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers)
# token = sf_sync_config['token']
# sf_secret_key = sf_sync_config['sf_secret_key'] def get_sync_real_time_distribution_functional_tools(self, objs_all, str_url, token, headers):
# headers = Common.get_headers(self, token, sf_secret_key) tool_distribution_list = []
# str_url = sf_sync_config['sf_url'] + self.crea_url try:
# objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([('id', '=', self.id)]) if objs_all:
# self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers) for item in objs_all:
# functional_tool_codes = []
# def sync_enroll_functional_tool_real_time_distribution_all(self): for obj in item.sf_functional_tool_entity_ids:
# logging.info('调用功能刀具安全库存注册接口: sync_enroll_functional_tool_real_time_distribution_all()') functional_tool_codes.append(obj.code)
# sf_sync_config = self.env['res.config.settings'].get_values() val = {
# token = sf_sync_config['token'] 'id': item.id,
# sf_secret_key = sf_sync_config['sf_secret_key'] 'name': item.name,
# headers = Common.get_headers(self, token, sf_secret_key) 'tool_groups_name': item.tool_groups_id.name,
# str_url = sf_sync_config['sf_url'] + self.crea_url 'cutting_tool_type_code': item.sf_cutting_tool_type_id.code,
# objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([]) 'diameter': item.diameter,
# self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers) 'knife_tip_r_angle': item.knife_tip_r_angle,
# 'tool_stock_num': item.tool_stock_num,
# def get_sync_real_time_distribution_functional_tools(self, objs_all, str_url, token, headers): 'side_shelf_num': item.side_shelf_num,
# tool_distribution_list = [] 'on_tool_stock_num': item.on_tool_stock_num,
# try: 'tool_stock_total': item.tool_stock_total,
# if objs_all: 'min_stock_num': item.min_stock_num,
# for item in objs_all: 'max_stock_num': item.max_stock_num,
# functional_tool_codes = [] 'batch_replenishment_num': item.batch_replenishment_num,
# for obj in item.sf_functional_tool_entity_ids: 'unit': item.unit,
# functional_tool_codes.append(obj.code) 'image': '' if not item.image else base64.b64encode(item.image).decode('utf-8'),
# val = { 'functional_tool_codes': str(functional_tool_codes),
# 'id': item.id, 'coarse_middle_thin': item.coarse_middle_thin,
# 'name': item.name, 'whether_standard_knife': item.whether_standard_knife,
# 'tool_groups_name': item.tool_groups_id.name, 'suitable_machining_method_names': get_suitable_machining_method_names(item),
# 'cutting_tool_type_code': item.sf_cutting_tool_type_id.code, 'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name,
# 'diameter': item.diameter, 'handle_type_name': item.handle_type_id.name,
# 'knife_tip_r_angle': item.knife_tip_r_angle, 'cutting_direction_names': get_cutting_direction_names(item),
# 'tool_stock_num': item.tool_stock_num, 'suitable_coolant_names': get_suitable_coolant_names(item),
# 'side_shelf_num': item.side_shelf_num, 'active': item.active
# 'on_tool_stock_num': item.on_tool_stock_num, }
# 'tool_stock_total': item.tool_stock_total, tool_distribution_list.append(val)
# 'min_stock_num': item.min_stock_num, kw = json.dumps(tool_distribution_list, ensure_ascii=False)
# 'max_stock_num': item.max_stock_num, r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
# 'batch_replenishment_num': item.batch_replenishment_num, ret = r.json()
# 'unit': item.unit, if ret.get('code') == 200:
# 'image': '' if not item.image else base64.b64encode(item.image).decode('utf-8'), return "功能刀具出入库记录注册成功"
# 'functional_tool_codes': str(functional_tool_codes), else:
# 'coarse_middle_thin': item.coarse_middle_thin, logging.info('没有注册功能刀具出入库记录信息')
# 'whether_standard_knife': item.whether_standard_knife, except Exception as e:
# 'suitable_machining_method_names': get_suitable_machining_method_names(item), logging.info("捕获错误信息:%s" % e)
# 'blade_tip_characteristics_name': item.blade_tip_characteristics_id.name,
# 'handle_type_name': item.handle_type_id.name,
# 'cutting_direction_names': get_cutting_direction_names(item),
# 'suitable_coolant_names': get_suitable_coolant_names(item),
# 'active': item.active
# }
# tool_distribution_list.append(val)
# kw = json.dumps(tool_distribution_list, ensure_ascii=False)
# r = requests.post(str_url, json={}, data={'kw': kw, 'token': token}, headers=headers)
# ret = r.json()
# if ret.get('code') == 200:
# return "功能刀具出入库记录注册成功"
# else:
# logging.info('没有注册功能刀具出入库记录信息')
# except Exception as e:
# logging.info("捕获错误信息:%s" % e)
#
# @api.model_create_multi
# def create(self, vals_list):
# records = super(RealTimeDistributionFunctionalTools, self).create(vals_list)
# for record in records:
# if record:
# record.enroll_functional_tool_real_time_distribution()
# return records
#
# def write(self, vals):
# res = super().write(vals)
# if vals.get('sf_functional_tool_entity_ids') or vals.get('min_stock_num') or vals.get('max_stock_num'):
# self.enroll_functional_tool_real_time_distribution()
# return res

View File

@@ -61,6 +61,12 @@ class SfMaintenanceEquipment(models.Model):
def write_maintenance_equipment_tool(self, datas): def write_maintenance_equipment_tool(self, datas):
if datas: if datas:
# 清除设备机床刀位的刀具信息
for obj in self.product_template_ids:
obj.write({
'functional_tool_name_id': False,
'tool_install_time': None
})
for data in datas: for data in datas:
maintenance_equipment_id = self.search([('name', '=', data['DeviceId'])]) maintenance_equipment_id = self.search([('name', '=', data['DeviceId'])])
if maintenance_equipment_id: if maintenance_equipment_id:
@@ -128,12 +134,9 @@ class StockLot(models.Model):
record.tool_material_status = '报废' record.tool_material_status = '报废'
else: else:
record.tool_material_status = '未入库' record.tool_material_status = '未入库'
# if record.tool_material_search_id: if record.fixture_material_search_id:
# # 注册具物料状态到cloud平台 # 注册具物料状态到cloud平台
# record.enroll_tool_material_stock() record.enroll_fixture_material_stock()
# elif record.fixture_material_search_id:
# # 注册夹具物料状态到cloud平台
# record.enroll_fixture_material_stock()
@api.model @api.model
def name_search(self, name='', args=None, operator='ilike', limit=100): def name_search(self, name='', args=None, operator='ilike', limit=100):

View File

@@ -45,8 +45,8 @@ class ToolMaterial(models.Model):
record.have_been_used_num = have_been_used_num record.have_been_used_num = have_been_used_num
record.scrap_num = scrap_num record.scrap_num = scrap_num
record.number = usable_num + have_been_used_num + scrap_num record.number = usable_num + have_been_used_num + scrap_num
# 更新数据到cloud的动态数据
# record.enroll_tool_material()
@api.model @api.model
def _read_group_cutting_tool_material_id(self, categories, domain, order): def _read_group_cutting_tool_material_id(self, categories, domain, order):

View File

@@ -859,14 +859,36 @@ class SfStockPicking(models.Model):
check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in') check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in')
def batch_stock_move(self):
"""
批量调拨,非就绪状态的会被忽略,完成后有通知提示
"""
for record in self:
if record.state != 'assigned':
continue
record.action_set_quantities_to_reservation()
record.button_validate()
notification_message = '批量调拨完成!请注意,状态非就绪的单据会被忽略'
return {
'effect': {
'fadeout': 'fast',
'message': notification_message,
'img_url': '/web/image/%s/%s/image_1024' % (
self.create_uid._name, self.create_uid.id) if 0 else '/web/static/img/smile.svg',
'type': 'rainbow_man',
}
}
@api.depends('name') @api.depends('name')
def _check_is_in(self): def _check_is_in(self):
""" """
判断是否为出库单 判断是否为出库单
""" """
if self.name: for record in self:
is_check_in = self.name.split('/') if record.name:
self.check_in = is_check_in[1] is_check_in = record.name.split('/')
record.check_in = is_check_in[1]
def button_validate(self): def button_validate(self):
""" """

View File

@@ -149,6 +149,9 @@
<button name="action_assign" type="object" string="检查可用量" <button name="action_assign" type="object" string="检查可用量"
groups="sf_base.group_sf_stock_user"/> groups="sf_base.group_sf_stock_user"/>
</xpath> </xpath>
<xpath expr="//header" position="inside">
<button name="batch_stock_move" type='object' string="批量调拨"/>
</xpath>
</field> </field>
</record> </record>