Compare commits

...

15 Commits

Author SHA1 Message Date
yuxianghui
b8894609a9 功能刀具寿命到期消息通知 2025-06-12 10:10:13 +08:00
yuxianghui
3f8fd6da62 创建刀具拆解单判断条件优化 2025-06-12 09:40:32 +08:00
yuxianghui
62ead52f00 处理功能刀具预警时没有创建功能刀具预警记录和功能刀具拆解单bug 2025-06-11 17:18:59 +08:00
胡尧
8841d800ea Merge branch 'hotfix/备注为空' into release/release_2.14 2025-06-11 11:28:35 +08:00
guanhuan
920e96ffc6 修复备注为空 2025-06-11 11:19:31 +08:00
yuxianghui
d52f5fa841 修复取消订单时报错bug 2025-06-11 11:15:03 +08:00
胡尧
e0559e9887 Merge branch 'develop' into release/release_2.14 2025-06-10 16:33:57 +08:00
管欢
39a25bb6c8 Accept Merge Request #2180: (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/2180
2025-06-10 16:33:37 +08:00
禹翔辉
e129c08426 Accept Merge Request #2179: (feature/bfm下单接口优化 -> 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/2179
2025-06-10 15:28:17 +08:00
yuxianghui
c6b47bd68d 销售订单新增合同日期字段 2025-06-10 15:26:32 +08:00
guanhuan
126d60f8d7 Merge branch 'refs/heads/feature/搜索优化' into release/release_2.14 2025-06-10 10:45:52 +08:00
guanhuan
4225a8fe1b 采购申请单完成操作提示调整 2025-06-10 10:45:06 +08:00
guanhuan
a13a79f41f Merge branch 'refs/heads/feature/搜索优化' into release/release_2.14 2025-06-09 17:56:50 +08:00
guanhuan
a828c823dd 采购申请单完成操作修改 2025-06-09 17:55:34 +08:00
guanhuan
9cf2bac9c6 修复返工问题 2025-06-09 17:39:55 +08:00
11 changed files with 123 additions and 112 deletions

View File

@@ -41,13 +41,14 @@ class PurchaseRequest(models.Model):
if lines:
for line in lines:
for line_item in line.order_line:
product_id = line_item.product_id.id
qty = line_item.product_qty
product_rounding[product_id] = line_item.product_id.uom_id.rounding
if product_id in product_summary:
product_summary[product_id] += qty
else:
product_summary[product_id] = qty
if line_item.state == 'purchase':
product_id = line_item.product_id.id
qty = line_item.product_qty
product_rounding[product_id] = line_item.product_id.uom_id.rounding
if product_id in product_summary:
product_summary[product_id] += qty
else:
product_summary[product_id] = qty
# 校验产品数量
discrepancies = []
@@ -60,10 +61,10 @@ class PurchaseRequest(models.Model):
if discrepancies:
# 弹出提示框
message = "产品数量不一致:\n"
message = "产品与采购数量不一致:\n"
for product_id, required_qty, order_qty in discrepancies:
product_name = self.env['product.product'].browse(product_id).display_name # 获取产品名称
message += f"产品 {product_name},需求数量 {required_qty},关联采购订单数量 {order_qty}(含询价状态)\n"
message += f"产品 {product_name},需求数量 {required_qty},关联采购订单确认的数量 {order_qty}\n"
# 添加确认框
message += "确认关闭?"
return {

View File

@@ -445,32 +445,7 @@ class Manufacturing_Connect(http.Controller):
shelfinfo = list(filter(lambda x: x.get('DeviceId') == DeciveId,
request.env['sf.shelf.location'].sudo().get_sf_shelf_location_info(
DeciveId)))
total_data = request.env['sf.shelf.location.datasync'].sudo().get_total_data()
for item in shelfinfo:
logging.info('货架已获取信息:%s' % item)
shelf_barcode = request.env['sf.shelf.location.datasync'].sudo().find_our_code(
total_data, item['Postion'])
location_id = request.env['sf.shelf.location'].sudo().search(
[('barcode', '=', shelf_barcode)],
limit=1)
if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = request.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.sudo().tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
# 修改功能刀具状态
if item.get('State') == '报警':
if tool.functional_tool_status != item.get('State'):
tool.write({
'functional_tool_status': item['State']
})
else:
location_id.product_sn_id = False
if item['RfidCode']:
logging.info('Rfid为【%s】的功能刀具在系统中不存在!' % item['RfidCode'])
request.env['sf.shelf.location.datasync'].sudo().set_shelf_location(shelfinfo)
else:
equipment_id = request.env['maintenance.equipment'].sudo().search([('name', '=', DeciveId)])
if equipment_id:

View File

@@ -27,7 +27,7 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
bfm_process_order_list = json.loads(kw['bfm_process_order_list'])
order_id = request.env['sale.order'].with_user(request.env.ref("base.user_admin")).sale_order_create(
company_id, kw['delivery_name'], kw['delivery_telephone'], kw['delivery_address'],
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], state='draft',
kw['delivery_end_date'], kw['payments_way'], kw['pay_way'], kw['order_number'], kw['remark'], state='draft',
model_display_version=kw.get('model_display_version'))
i = 1
# 给sale_order的default_code字段赋值
@@ -47,7 +47,7 @@ class JikimoSaleRoutePicking(Sf_Bf_Connect):
i += 1
if kw.get('contract_file_name') and kw.get('contract_file') and kw.get('contract_code'):
order_id.create_sale_documents(kw.get('contract_file_name'), kw.get('contract_file'))
order_id.write({'contract_code': kw.get('contract_code')})
order_id.write({'contract_code': kw.get('contract_code'), 'contract_date': kw.get('contract_date')})
res['factory_order_no'] = order_id.name
order_id.confirm_to_supply_method()
except Exception as e:

View File

@@ -227,22 +227,30 @@ class ResMrpWorkOrder(models.Model):
# finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0
else:
next_workorder = sorted_workorders[position + 1]
next_state = next_workorder.state
if next_state not in ['pending', 'waiting', 'ready']:
raise UserError('下工序已经开始,无法回退')
if next_workorder.is_subcontract:
next_workorder.picking_ids.write({'state': 'waiting'})
next_workorder.state = 'pending'
self.time_ids.date_end = None
cur_workorder.state = 'progress'
cur_workorder.production_id.state = 'progress'
quality_check = self.env['quality.check'].search(
[('workorder_id', '=', self.id)])
for check_order in quality_check:
if check_order.point_id.is_inspect:
check_order.quality_state = 'waiting'
# 持续获取下一个工单,直到找到一个不是返工的工单
while next_workorder and next_workorder.state == 'rework':
position += 1
if position + 1 < len(sorted_workorders):
next_workorder = sorted_workorders[position + 1]
else:
check_order.quality_state = 'none'
next_workorder = None
if next_workorder:
next_state = next_workorder.state
if next_state not in ['pending', 'waiting', 'ready']:
raise UserError('下工序已经开始,无法回退')
if next_workorder.is_subcontract:
next_workorder.picking_ids.write({'state': 'waiting'})
next_workorder.state = 'pending'
self.time_ids.date_end = None
cur_workorder.state = 'progress'
cur_workorder.production_id.state = 'progress'
quality_check = self.env['quality.check'].search(
[('workorder_id', '=', self.id)])
for check_order in quality_check:
if check_order.point_id.is_inspect:
check_order.quality_state = 'waiting'
else:
check_order.quality_state = 'none'
def _compute_working_users(self):
super()._compute_working_users()

View File

@@ -210,8 +210,8 @@
<field name="msgtype">markdown</field>
<field name="urgency">normal</field>
<field name="content">### 功能刀具寿命到期提醒:
单号:拆解单[{{code}}]({{tool_expired_remind_special_url}})
事项:{{functional_tool_id.tool_name_id.name}}寿命已到期,需拆解</field>
单号:拆解单[{{code}}]({{request_url}})
事项:{{name}}寿命已到期,需拆解</field>
</record>
<record id="template_tool_assembly_remind" model="jikimo.message.template">

View File

@@ -1,4 +1,5 @@
from odoo import models, api
from urllib.parse import urlencode
class SFMessagefunctionalToolDismantle(models.Model):
@@ -18,12 +19,39 @@ class SFMessagefunctionalToolDismantle(models.Model):
obj.add_queue('功能刀具寿命到期')
return result
def get_special_url(self,id,tmplate_name,special_name,model_id):
def _get_message(self, message_queue_ids):
contents = []
for message_queue_id in message_queue_ids:
if message_queue_id.message_template_id.name == '功能刀具寿命到期':
content = message_queue_id.message_template_id.content
td_line = self.search([('id', '=', int(message_queue_id.res_id))])
url = self.request_url(int(message_queue_id.res_id))
content = content.replace('{{code}}', td_line.code).replace(
'{{request_url}}', url).replace('{{name}}', td_line.name)
contents.append(content)
return contents, message_queue_ids
def request_url(self, id):
url = self.env['ir.config_parameter'].get_param('web.base.url')
action_id = self.env.ref('sf_tool_management.sf_functional_tool_dismantle_view_act').id
menu_id = self.env.ref('sf_tool_management.menu_sf_functional_tool_dismantle').id
# 查询参数
params = {'id': id, 'menu_id': menu_id, 'action': action_id,
'model': 'sf.functional.tool.dismantle',
'view_type': 'form'}
# 拼接查询参数
tool_string = urlencode(params)
# 拼接URL
full_url = url + "/web#" + tool_string
return full_url
def get_special_url(self, id, tmplate_name, special_name, model_id):
menu_id = 0
action_id = 0
if tmplate_name=='调拨入库' and special_name== 'tool_expired_remind_special_url':
if tmplate_name == '调拨入库' and special_name == 'tool_expired_remind_special_url':
menu_id = self.env.ref('mrp.menu_mrp_root').id
action_id = self.env.ref('sf_tool_management.sf_functional_tool_dismantle_view_act').id
return super(SFMessagefunctionalToolDismantle, self).get_url(id, menu_id, action_id,model_id)
return super(SFMessagefunctionalToolDismantle, self).get_url(id, menu_id, action_id, model_id)
else:
return super(SFMessagefunctionalToolDismantle, self).get_special_url(id, tmplate_name, special_name, model_id)
return super(SFMessagefunctionalToolDismantle, self).get_special_url(id, tmplate_name, special_name,
model_id)

View File

@@ -43,14 +43,17 @@ class SFMessageQualityCheck(models.Model):
# ('message_template_id', '=', message_template.id)])
# return jikimo_message_queue
def write(self, vals):
original_state = self.quality_state
original_state = {}
for item in self:
original_state.update({f'{item.id}': item.quality_state})
res = super(SFMessageQualityCheck, self).write(vals)
if res and vals.get('quality_state') == 'none' and original_state != 'none':
message_template_id = self.env['jikimo.message.template'].sudo().search([('name', '=', '待质检提醒')])
queue_id = self.env['jikimo.message.queue'].sudo().search(
[('message_template_id', '=', message_template_id[-1].id), ('res_id', '=', self.id)])
if not queue_id and '制造' not in [pt.name for pt in self.point_id.picking_type_ids]:
self.add_queue('待质检')
for item in self:
if vals.get('quality_state') == 'none' and original_state.get(f'{item.id}') != 'none':
message_template_id = self.env['jikimo.message.template'].sudo().search([('name', '=', '待质检提醒')])
queue_id = self.env['jikimo.message.queue'].sudo().search(
[('message_template_id', '=', message_template_id[-1].id), ('res_id', '=', item.id)])
if not queue_id and '制造' not in [pt.name for pt in item.point_id.picking_type_ids]:
item.add_queue('待质检')
return res
def _get_message(self, message_queue_ids):

View File

@@ -64,13 +64,14 @@ class ReSaleOrder(models.Model):
model_display_version = fields.Char('模型展示版本', default="v1")
contract_code = fields.Char('合同编号')
contract_date = fields.Date('合同日期')
contract_document_id = fields.Many2one('documents.document', string='合同文件')
contract_file = fields.Binary(related='contract_document_id.datas', string='合同文件内容')
contract_file_name = fields.Char(related='contract_document_id.attachment_id.name', string='文件名')
# 业务平台分配工厂后在智能工厂先创建销售订单
def sale_order_create(self, company_id, delivery_name, delivery_telephone, delivery_address,
deadline_of_delivery, payments_way, pay_way, order_number, state='sale',
deadline_of_delivery, payments_way, pay_way, order_number, remark, state='sale',
model_display_version='v1'):
now_time = datetime.datetime.now()
partner = self.get_customer()
@@ -89,6 +90,7 @@ class ReSaleOrder(models.Model):
'pay_way': pay_way,
'order_code': order_number,
'model_display_version': model_display_version,
'remark': remark,
}
if deadline_of_delivery:
# deadline_of_delivery字段存在为false字符串情况

View File

@@ -58,20 +58,6 @@ class FunctionalCuttingToolEntity(models.Model):
safe_inventory_id = fields.Many2one('sf.real.time.distribution.of.functional.tools',
string='功能刀具安全库存', readonly=True)
@api.onchange('functional_tool_status')
def _onchange_functional_tool_status(self):
for item in self:
if item:
if item.functional_tool_status == '报警':
self.create_tool_dismantle()
def set_functional_tool_status(self):
# self.write({
# 'functional_tool_status': '报警'
# })
self.functional_tool_status = '报警'
self.create_tool_dismantle()
def create_tool_dismantle(self):
for item in self:
# 创建报警刀具拆解单

View File

@@ -42,7 +42,6 @@
<field name="arch" type="xml">
<form create="0" edit="0" delete="0">
<header>
<button name="set_functional_tool_status" string="报警" type="object" invisible="1"/>
<!-- <button name="enroll_functional_tool_entity" string="功能刀具注册" type="object"-->
<!-- class="btn-primary"/>-->
<field name="functional_tool_status" widget="statusbar" statusbar_visible="正常,报警,已拆除"/>

View File

@@ -107,38 +107,47 @@ class MrsShelfLocationDataSync(models.Model):
equipment_id.register_equipment_tool()
shelfinfo = self.env['sf.shelf.location'].get_sf_shelf_location_info()
total_data = self.get_total_data()
print('shelfinfo:', shelfinfo)
for item in shelfinfo:
logging.info('货架已获取信息:%s' % item)
shelf_barcode = self.find_our_code(total_data, item['Postion'])
location_id = self.env['sf.shelf.location'].search([('barcode', '=', shelf_barcode)], limit=1)
if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
# 修改功能刀具标准状态值和已使用寿命值、功能刀具状态
if 'LifeStd' in item and 'LifeUse' in item:
tool.sudo().write({
'max_lifetime_value': item['LifeStd'],
'used_value': item['LifeUse'],
'functional_tool_status': item['State'],
})
else:
location_id.product_sn_id = False
if item['RfidCode']:
logging.info('Rfid为【%s】的功能刀具在系统中不存在!' % item['RfidCode'])
else:
stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1)
if stock_lot_obj:
location_id.product_sn_id = stock_lot_obj.id
else:
location_id.product_sn_id = False
self.set_shelf_location(shelfinfo)
except Exception as e:
logging.info("库区信息同步失败:%s" % e)
raise ValidationError("数据错误导致同步失败,请联系管理员")
def set_shelf_location(self, shelfinfo):
print('shelfinfo:', shelfinfo)
total_data = self.get_total_data()
for item in shelfinfo:
logging.info('货架已获取信息:%s' % item)
shelf_barcode = self.env['sf.shelf.location.datasync'].sudo().find_our_code(
total_data, item['Postion'])
location_id = self.env['sf.shelf.location'].sudo().search(
[('barcode', '=', shelf_barcode)],
limit=1)
if location_id:
# 如果是线边刀库信息,则对功能刀具移动生成记录
if 'Tool' in item['Postion']:
tool = self.env['sf.functional.cutting.tool.entity'].sudo().search(
[('rfid', '=', item['RfidCode']), ('functional_tool_status', '!=', '已拆除')])
tool.sudo().tool_in_out_stock_location(location_id)
if tool:
location_id.product_sn_id = tool.barcode_id.id
if item.get('State') == '报警' and tool.functional_tool_status != '报警':
# 创建报警刀具拆解单和刀具报警记录
tool.create_tool_dismantle()
# 修改功能刀具标准状态值和已使用寿命值、功能刀具状态
if 'LifeStd' in item and 'LifeUse' in item:
tool.sudo().write({
'max_lifetime_value': item['LifeStd'],
'used_value': item['LifeUse'],
'functional_tool_status': item['State'],
})
else:
location_id.product_sn_id = False
if item['RfidCode']:
logging.info('Rfid为【%s】的功能刀具在系统中不存在!' % item['RfidCode'])
else:
stock_lot_obj = self.env['stock.lot'].search([('rfid', '=', item['RfidCode'])], limit=1)
if stock_lot_obj:
location_id.product_sn_id = stock_lot_obj.id
else:
location_id.product_sn_id = False