Merge remote-tracking branch 'origin/develop' into develop

# Conflicts:
#	sf_manufacturing/models/mrp_production.py
#	sf_manufacturing/models/purchase_order.py
#	sf_sale/models/sale_order.py
This commit is contained in:
liaodanlong
2025-04-27 08:50:45 +08:00
10 changed files with 77 additions and 32 deletions

View File

@@ -32,6 +32,7 @@ class PurchaseRequestLineMakePurchaseOrder(models.TransientModel):
line.company_id, line.company_id,
line.request_id.origin, line.request_id.origin,
) )
# po_data.update({'related_product':line.related_product.id})
purchase = purchase_obj.create(po_data) purchase = purchase_obj.create(po_data)
# Look for any other PO line in the selected PO with same # Look for any other PO line in the selected PO with same
@@ -63,6 +64,8 @@ class PurchaseRequestLineMakePurchaseOrder(models.TransientModel):
po_line_data = self._prepare_purchase_order_line(purchase, item) po_line_data = self._prepare_purchase_order_line(purchase, item)
if item.keep_description: if item.keep_description:
po_line_data["name"] = item.name po_line_data["name"] = item.name
if line.related_product:
po_line_data.update({'related_product': line.related_product.id})
po_line = po_line_obj.create(po_line_data) po_line = po_line_obj.create(po_line_data)
po_line_product_uom_qty = po_line.product_uom._compute_quantity( po_line_product_uom_qty = po_line.product_uom._compute_quantity(
po_line.product_uom_qty, alloc_uom po_line.product_uom_qty, alloc_uom

View File

@@ -1,7 +1,7 @@
import json import json
from odoo import http from odoo import http
from odoo.http import request from odoo.http import request
from odoo.addons.sf_machine_connect.models.ftp_operate import transfer_nc_files from odoo.addons.sf_machine_connect.models.ftp_operate import transfer_files
from odoo.addons.sf_base.decorators.api_log import api_log from odoo.addons.sf_base.decorators.api_log import api_log
class MainController(http.Controller): class MainController(http.Controller):
@@ -54,15 +54,15 @@ class MainController(http.Controller):
} }
# 传输nc文件 # 传输nc文件
try: try:
result = transfer_nc_files( result = transfer_files(
source_ftp_info, source_ftp_info,
target_ftp_info, target_ftp_info,
'/' + str(model_id), '/' + str(model_id),
'/', '/',
match_str=r'^\d*_\d*-' + tool_groups_id.name + r'-\w{2}-all\.nc$' match_str=r'^\d*_\d*-' + tool_groups_id.name + r'-\w{2}-all\.nc$'
) )
if result: if len(result) > 0:
return {'code': 200, 'message': 'success'} return {'code': 200, 'message': '传输成功', 'file_list': result}
else: else:
return {'code': 404, 'message': '未找到编程文件'} return {'code': 404, 'message': '未找到编程文件'}
except Exception as e: except Exception as e:

View File

@@ -167,10 +167,10 @@ class PrintingUtils(models.AbstractModel):
# 设置字体 # 设置字体
if font_found: if font_found:
c.setFont('SimSun', 14) # 增大字体大小到14pt c.setFont('SimSun', 10) # 增大字体大小到14pt
else: else:
# 如果没有找到中文字体,使用默认字体 # 如果没有找到中文字体,使用默认字体
c.setFont('Helvetica', 14) c.setFont('Helvetica', 10)
logging.warning("未找到中文字体,将使用默认字体") logging.warning("未找到中文字体,将使用默认字体")
# 在右下角绘制二维码,预留边距 # 在右下角绘制二维码,预留边距
@@ -182,7 +182,7 @@ class PrintingUtils(models.AbstractModel):
if buttom_text: if buttom_text:
# 在二维码下方绘制文字 # 在二维码下方绘制文字
text = buttom_text text = buttom_text
text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 14) # 准确计算文字宽度 text_width = c.stringWidth(text, "SimSun" if font_found else "Helvetica", 10) # 准确计算文字宽度
text_x = page_width - qr_size - margin + (qr_size - text_width) / 2 # 文字居中对齐 text_x = page_width - qr_size - margin + (qr_size - text_width) / 2 # 文字居中对齐
text_y = margin + 20 # 文字位置靠近底部 text_y = margin + 20 # 文字位置靠近底部
c.drawString(text_x, text_y, text) c.drawString(text_x, text_y, text)

View File

@@ -1300,9 +1300,6 @@ class Sf_Dashboard_Connect(http.Controller):
machine_list = ast.literal_eval(kw['machine_list']) machine_list = ast.literal_eval(kw['machine_list'])
time_threshold = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0) time_threshold = datetime.now().replace(hour=0, minute=0, second=0, microsecond=0)
alarm_last_24_time = 0.0
alarm_all_time = 0.0
def fetch_result_as_dict(cursor): def fetch_result_as_dict(cursor):
"""辅助函数:将查询结果转为字典""" """辅助函数:将查询结果转为字典"""
columns = [desc[0] for desc in cursor.description] columns = [desc[0] for desc in cursor.description]
@@ -1311,6 +1308,9 @@ class Sf_Dashboard_Connect(http.Controller):
# 获取当前时间的时间戳 # 获取当前时间的时间戳
current_timestamp = datetime.now().timestamp() current_timestamp = datetime.now().timestamp()
for item in machine_list: for item in machine_list:
alarm_last_24_time = 0.0
alarm_all_time = 0.0
euipment_obj = request.env['maintenance.equipment'].sudo().search([('code', '=', item)]) euipment_obj = request.env['maintenance.equipment'].sudo().search([('code', '=', item)])
# 机床上线时间段 # 机床上线时间段
first_online_duration = current_timestamp - euipment_obj.first_online_time.timestamp() first_online_duration = current_timestamp - euipment_obj.first_online_time.timestamp()
@@ -1360,9 +1360,9 @@ class Sf_Dashboard_Connect(http.Controller):
if result[0]: if result[0]:
if float(result[0]) >= 28800: if float(result[0]) >= 28800:
continue continue
alarm_last_24_time = float(result[0]) alarm_last_24_time += float(result[0])
else: else:
alarm_last_24_time = 0.0 alarm_last_24_time += 0.0
alarm_all_nums = [] alarm_all_nums = []
with conn.cursor() as cur: with conn.cursor() as cur:

View File

@@ -9,9 +9,13 @@ _logger = logging.getLogger(__name__)
class FTP_P(FTP): class FTP_P(FTP):
""" """
重写FTP类重写dirs方法 重写FTP类重写dirs方法,增加编码处理
""" """
def __init__(self, host='', user='', passwd='', acct='', timeout=None, encoding='gbk'):
"""初始化时指定编码方式"""
super().__init__(host, user, passwd, acct, timeout)
self.encoding = encoding
def dirs(self, *args): def dirs(self, *args):
"""List a directory in long form. """List a directory in long form.
By default list current directory to stdout. By default list current directory to stdout.
@@ -32,7 +36,50 @@ class FTP_P(FTP):
tempdic['name'] = [file for file in r_files if file != "." and file != ".."] tempdic['name'] = [file for file in r_files if file != "." and file != ".."]
# 去除. .. # 去除. ..
return tempdic return tempdic
# return [file for file in r_files if file != "." and file != ".."]
def nlst(self, *args):
"""Get a list of files in a directory."""
files = []
def append(line):
try:
if isinstance(line, bytes):
files.append(line.decode(self.encoding))
else:
files.append(line)
except UnicodeDecodeError:
files.append(line.decode('utf-8', errors='replace'))
cmd = 'NLST'
if args:
cmd = cmd + ' ' + args[0]
self.retrlines(cmd, append)
return files
def cwd(self, dirname):
"""Change to a directory."""
try:
if isinstance(dirname, bytes):
dirname = dirname.decode(self.encoding)
return super().cwd(dirname)
except UnicodeEncodeError:
return super().cwd(dirname.encode(self.encoding).decode('utf-8'))
def storbinary(self, cmd, fp, blocksize=8192, callback=None, rest=None):
"""Store a file in binary mode."""
try:
if isinstance(cmd, bytes):
cmd = cmd.decode(self.encoding)
return super().storbinary(cmd, fp, blocksize, callback, rest)
except UnicodeEncodeError:
return super().storbinary(cmd.encode(self.encoding).decode('utf-8'), fp, blocksize, callback, rest)
def retrbinary(self, cmd, callback, blocksize=8192, rest=None):
"""Retrieve a file in binary mode."""
try:
if isinstance(cmd, bytes):
cmd = cmd.decode(self.encoding)
return super().retrbinary(cmd, callback, blocksize, rest)
except UnicodeEncodeError:
return super().retrbinary(cmd.encode(self.encoding).decode('utf-8'), callback, blocksize, rest)
# FTP接口类 # FTP接口类
@@ -133,7 +180,7 @@ class FtpController:
def transfer_nc_files( def transfer_files(
source_ftp_info, source_ftp_info,
target_ftp_info, target_ftp_info,
source_dir, source_dir,
@@ -151,7 +198,7 @@ def transfer_nc_files(
target_dir: str, 目标FTP上的目标目录 target_dir: str, 目标FTP上的目标目录
keep_dir: bool, 是否保持目录结构,默认False keep_dir: bool, 是否保持目录结构,默认False
""" """
trans_status = [False] transfered_file_list = []
try: try:
# 连接源FTP # 连接源FTP
source_ftp = FtpController( source_ftp = FtpController(
@@ -217,7 +264,7 @@ def transfer_nc_files(
with open(temp_path, 'rb') as f: with open(temp_path, 'rb') as f:
target_ftp.ftp.storbinary(f'STOR {target_path}', f) target_ftp.ftp.storbinary(f'STOR {target_path}', f)
trans_status[0] = True transfered_file_list.append(item)
# 删除临时文件 # 删除临时文件
os.remove(temp_path) os.remove(temp_path)
logging.info(f"已传输文件: {item}") logging.info(f"已传输文件: {item}")
@@ -259,7 +306,7 @@ def transfer_nc_files(
traverse_dir(source_dir) traverse_dir(source_dir)
logging.info("所有文件传输完成") logging.info("所有文件传输完成")
return trans_status[0] return transfered_file_list
except Exception as e: except Exception as e:
logging.error(f"传输过程出错: {str(e)}") logging.error(f"传输过程出错: {str(e)}")

View File

@@ -1245,7 +1245,8 @@ class ResMrpWorkOrder(models.Model):
return workorders_values_str return workorders_values_str
def _process_compute_state(self): def _process_compute_state(self):
for workorder in self: sorted_workorders = sorted(self, key=lambda x: x.sequence)
for workorder in sorted_workorders:
# 如果工单的工序没有进行排序则跳出循环 # 如果工单的工序没有进行排序则跳出循环
if workorder.production_id.workorder_ids.filtered(lambda wk: wk.sequence == 0): if workorder.production_id.workorder_ids.filtered(lambda wk: wk.sequence == 0):
continue continue
@@ -1304,13 +1305,6 @@ class ResMrpWorkOrder(models.Model):
workorder.state = 'ready' workorder.state = 'ready'
elif workorder.state != 'waiting': elif workorder.state != 'waiting':
workorder.state = 'waiting' workorder.state = 'waiting'
# =========== 特殊工艺工单处理 ===================
# if workorder.routing_type == '表面工艺' and workorder.is_subcontrac:
# purchase_order = self.env['purchase.order'].search(
# [('origin', 'ilike', workorder.production_id.name)])
# if purchase_order.picking_ids.filtered(lambda p: p.state in ['waiting', 'confirmed', 'assigned']):
# workorder.state = 'waiting'
# continue
if workorder.technology_design_id.routing_tag == 'special': if workorder.technology_design_id.routing_tag == 'special':
if workorder.is_subcontract is False: if workorder.is_subcontract is False:
workorder.state = 'ready' workorder.state = 'ready'
@@ -1332,6 +1326,7 @@ class ResMrpWorkOrder(models.Model):
else: else:
workorder.state = 'waiting' workorder.state = 'waiting'
@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',
'production_id.tool_state', 'production_id.schedule_state', 'sequence', 'production_id.tool_state', 'production_id.schedule_state', 'sequence',
'production_id.programming_state') 'production_id.programming_state')

View File

@@ -95,7 +95,7 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
logging.info('panel_file_path:%s' % panel_file_path) logging.info('panel_file_path:%s' % panel_file_path)
# 向编程单中添加二维码 # 向编程单中添加二维码
request.env['printing.utils'].add_qr_code_to_pdf(panel_file_path, model_id, "扫码获取工单") request.env['printing.utils'].add_qr_code_to_pdf(panel_file_path, model_id, "模型ID%s" % model_id)
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())}) cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
pre_workorder = productions.workorder_ids.filtered( pre_workorder = productions.workorder_ids.filtered(
lambda ap: ap.routing_type in ['装夹预调', '人工线下加工'] and ap.state not in ['done', 'rework' lambda ap: ap.routing_type in ['装夹预调', '人工线下加工'] and ap.state not in ['done', 'rework'

View File

@@ -224,11 +224,11 @@ class sf_production_plan(models.Model):
return num return num
def do_production_schedule(self,date_planned_start): def do_production_schedule(self):
""" """
排程方法 排程方法
""" """
self.deal_processing_schedule(date_planned_start) self.deal_processing_schedule(self.date_planned_start)
for record in self: for record in self:
if not record.production_line_id: if not record.production_line_id:
raise ValidationError("未选择生产线") raise ValidationError("未选择生产线")

View File

@@ -40,5 +40,5 @@ class Action_Plan_All_Wizard(models.TransientModel):
self.plan_ids.date_planned_start = self.date_planned_start self.plan_ids.date_planned_start = self.date_planned_start
# 在这里添加您的逻辑来处理这些ID # 在这里添加您的逻辑来处理这些ID
# 判断能否排成 # 判断能否排成
self.plan_ids.do_production_schedule(self.date_planned_start) self.plan_ids.do_production_schedule()
_logger.info('处理计划: %s 完成', self.plan_ids.ids) _logger.info('处理计划: %s 完成', self.plan_ids.ids)

View File

@@ -323,7 +323,7 @@ class RePurchaseOrder(models.Model):
contract_summary = fields.Text(string='合同概况') contract_summary = fields.Text(string='合同概况')
# 选择是否为紧急采购 # 选择是否为紧急采购
urgent_purchase = fields.Selection([('no', ''), ('yes', '')], string='紧急采购', default='no') urgent_purchase = fields.Selection([('no', ''), ('yes', '')], string='紧急采购', default='yes')
@api.depends('origin') @api.depends('origin')
def _compute_purchase_type(self): def _compute_purchase_type(self):