提交 2c0fb2dc authored 作者: 贺阳's avatar 贺阳

提单巡查

上级 d1f3003d
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
<field name='interval_type'>days</field> <field name='interval_type'>days</field>
<field name="numbercall">-1</field> <field name="numbercall">-1</field>
<field name="active" eval="True"/> <field name="active" eval="True"/>
<field name="nextcall" eval="(DateTime.now() + timedelta(hours=8)).strftime('%Y-%m-%d %H:%M:%S')"/> <field name="nextcall" eval="(DateTime.now().replace(hour=8, minute=0)).strftime('%Y-%m-%d %H:%M:%S')" />
<field name="doall" eval="False"/>
</record> </record>
</data> </data>
......
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
import re
from datetime import datetime, timedelta from datetime import datetime, timedelta
from odoo import models, fields, api, _ from odoo import models, fields, api, _
from odoo.exceptions import UserError from odoo.exceptions import UserError
...@@ -38,10 +39,16 @@ class BlPatrol(models.Model): ...@@ -38,10 +39,16 @@ class BlPatrol(models.Model):
""" """
try: try:
# 创建巡查记录 # 创建巡查记录
patrol = self.create({'name': f'提单巡查_{fields.Date.today()}','check_date': fields.Date.today(),'state': 'running'}) patrol = self.create({
# 执行巡查 'name': f'提单巡查_{fields.Date.today()}',
'check_date': fields.Date.today(),
'state': 'running'
})
# 执行巡查 提单日期为近x天(默认5天),清关中和完成的提单
result = patrol._execute_patrol() result = patrol._execute_patrol()
# 更新巡查记录
# 更新巡查记录
patrol.write({ patrol.write({
'state': 'done' if result['success'] else 'failed', 'state': 'done' if result['success'] else 'failed',
'bl_count': result['bl_count'], 'bl_count': result['bl_count'],
...@@ -55,9 +62,16 @@ class BlPatrol(models.Model): ...@@ -55,9 +62,16 @@ class BlPatrol(models.Model):
patrol._send_patrol_email(result) patrol._send_patrol_email(result)
_logger.info(f"提单巡查完成: {patrol.name}, 发现问题: {result['issue_count']}") _logger.info(f"提单巡查完成: {patrol.name}, 发现问题: {result['issue_count']}")
except Exception as e: except Exception as e:
_logger.error(f"提单巡查失败: {str(e)}") _logger.error(f"提单巡查失败: {str(e)}")
# 如果有巡查记录,更新状态为失败
if 'patrol' in locals():
patrol.write({
'state': 'failed',
'package_issues': f"巡查执行失败: {str(e)}",
'bl_issues': f"巡查执行失败: {str(e)}"
})
raise UserError(f"巡查失败: {str(e)}") raise UserError(f"巡查失败: {str(e)}")
def _execute_patrol(self): def _execute_patrol(self):
...@@ -76,19 +90,41 @@ class BlPatrol(models.Model): ...@@ -76,19 +90,41 @@ class BlPatrol(models.Model):
end_date = fields.Date.today() end_date = fields.Date.today()
start_date = end_date - timedelta(days=check_days) start_date = end_date - timedelta(days=check_days)
# 查找符合条件的提单 提单日期为近x天(默认5天),清关中和完成的提单。 # 查找符合条件的提单 提单日期为近x天(默认5天),清关中和完成的提单。
bls = self.env['cc.bl'].sudo().search([('create_date', '>=', start_date),('create_date', '<=', end_date),('state', 'in', ['ccing', 'completed'])]) bls = self.env['cc.bl'].sudo().search([('bl_date', '>=', start_date),('bl_date', '<=', end_date),('state', 'in', ['ccing', 'done'])])
_logger.info(f"开始巡查提单,检查范围: {start_date} 到 {end_date}, 提单数量: {len(bls)}") _logger.info(f"开始巡查提单,检查范围: {start_date} 到 {end_date}, 提单数量: {len(bls)}")
package_issues = [] package_issues = []
bl_issues = [] bl_issues = []
global_issue_counter = 1
for bl in bls: for bl in bls:
# 检查小包轨迹问题 # 检查小包轨迹问题
bl_package_issues = self._check_package_tracking_issues(bl) bl_package_issues = self._check_package_tracking_issues(bl)
if bl_package_issues: if bl_package_issues:
# 为小包问题添加全局编号
for i, issue in enumerate(bl_package_issues):
# 使用正则表达式匹配任何数字+顿号的格式
if re.match(r'^\d+、', issue):
# 替换开头的编号
bl_package_issues[i] = re.sub(r'^\d+、', f"{global_issue_counter}、", issue, 1)
else:
# 如果没有编号,添加编号
bl_package_issues[i] = f"{global_issue_counter}、{issue}"
global_issue_counter += 1
package_issues.extend(bl_package_issues) package_issues.extend(bl_package_issues)
# 检查提单关务节点问题 # 检查提单关务节点问题
bl_node_issues = self._check_bl_node_issues(bl) bl_node_issues = self._check_bl_node_issues(bl)
if bl_node_issues: if bl_node_issues:
# 为提单问题添加全局编号
for i, issue in enumerate(bl_node_issues):
# 使用正则表达式匹配任何数字+顿号的格式
if re.match(r'^\d+、', issue):
# 替换开头的编号
bl_node_issues[i] = re.sub(r'^\d+、', f"{global_issue_counter}、", issue, 1)
else:
# 如果没有编号,添加编号
bl_node_issues[i] = f"{global_issue_counter}、{issue}"
global_issue_counter += 1
bl_issues.extend(bl_node_issues) bl_issues.extend(bl_node_issues)
return { return {
...@@ -118,30 +154,56 @@ class BlPatrol(models.Model): ...@@ -118,30 +154,56 @@ class BlPatrol(models.Model):
current_log = sync_logs[i] current_log = sync_logs[i]
previous_log = sync_logs[i-1] previous_log = sync_logs[i-1]
if current_log.operate_time < previous_log.operate_time: if current_log.operate_time < previous_log.operate_time:
issue_key = f"{current_log.progress_name}({current_log.process_code})倒叙" try:
if issue_key not in reverse_issues: progress_name = current_log.progress_name or "空"
reverse_issues[issue_key] = [] process_code = current_log.process_code or "空"
reverse_issues[issue_key].append(package.logistic_order_no) issue_key = f"{progress_name}({process_code})倒叙"
if issue_key not in reverse_issues:
reverse_issues[issue_key] = []
reverse_issues[issue_key].append(package.logistic_order_no)
except Exception as e:
_logger.warning(f"构建小包倒叙问题描述失败: {str(e)}")
issue_key = "节点倒叙"
if issue_key not in reverse_issues:
reverse_issues[issue_key] = []
reverse_issues[issue_key].append(package.logistic_order_no)
break break
# 检查漏推问题 - 根据节点配置检查 # 检查漏推问题 - 根据节点配置检查
package_issues = self._check_package_missing_nodes(package, sync_logs) package_issues = self._check_package_missing_nodes(package, sync_logs)
for issue in package_issues: for issue in package_issues:
# 提取问题类型 # 提取问题类型
if "轨迹漏推" in issue: if "轨迹漏推" in issue:
issue_key = issue.split(",出现")[1].split(",涉及")[0] try:
if issue_key not in missing_issues: # 安全地提取问题类型,避免索引越界
missing_issues[issue_key] = [] if ",出现" in issue and ",涉及" in issue:
missing_issues[issue_key].append(package.logistic_order_no) issue_key = issue.split(",出现")[1].split(",涉及")[0]
else:
# 如果格式不匹配,使用整个问题描述作为key
issue_key = issue
if issue_key not in missing_issues:
missing_issues[issue_key] = []
missing_issues[issue_key].append(package.logistic_order_no)
except (IndexError, AttributeError) as e:
_logger.warning(f"解析小包问题失败: {issue}, 错误: {str(e)}")
# 使用整个问题描述作为key
issue_key = issue
if issue_key not in missing_issues:
missing_issues[issue_key] = []
missing_issues[issue_key].append(package.logistic_order_no)
# 格式化倒叙问题 # 格式化倒叙问题
issue_counter = 1
for issue_type, packages in reverse_issues.items(): for issue_type, packages in reverse_issues.items():
package_list = self._format_package_list(packages) package_list = self._format_package_list(packages)
issues.append(f"1.{bl.bl_no},出现{issue_type},涉及小包{len(packages)},小包追踪号包括{package_list}") issues.append(f"{issue_counter}、{bl.bl_no},出现{issue_type},涉及小包{len(packages)},小包追踪号包括{package_list}")
issue_counter += 1
# 格式化漏推问题 # 格式化漏推问题
for issue_type, packages in missing_issues.items(): for issue_type, packages in missing_issues.items():
package_list = self._format_package_list(packages) package_list = self._format_package_list(packages)
issues.append(f"1.{bl.bl_no},出现{issue_type},涉及小包{len(packages)},小包追踪号包括{package_list}") issues.append(f"{issue_counter}、{bl.bl_no},出现{issue_type},涉及小包{len(packages)},小包追踪号包括{package_list}")
issue_counter += 1
return issues return issues
...@@ -149,10 +211,20 @@ class BlPatrol(models.Model): ...@@ -149,10 +211,20 @@ class BlPatrol(models.Model):
""" """
格式化小包列表,最多显示10个 格式化小包列表,最多显示10个
""" """
if len(packages) <= 10: try:
return "/".join(packages) # 过滤掉None和空字符串
else: valid_packages = [pkg for pkg in packages if pkg and str(pkg).strip()]
return "/".join(packages[:10]) + "等"
if not valid_packages:
return "无有效追踪号"
if len(valid_packages) <= 10:
return "/".join(valid_packages)
else:
return "/".join(valid_packages[:10]) + "等"
except Exception as e:
_logger.warning(f"格式化小包列表失败: {str(e)}")
return "格式化失败"
def _check_package_missing_nodes(self, package, sync_logs): def _check_package_missing_nodes(self, package, sync_logs):
""" """
...@@ -173,6 +245,10 @@ class BlPatrol(models.Model): ...@@ -173,6 +245,10 @@ class BlPatrol(models.Model):
# 跳过当前节点(最后一个节点) # 跳过当前节点(最后一个节点)
if node == package_nodes[-1]: if node == package_nodes[-1]:
continue continue
# 跳过初始节点(is_default=True)
if getattr(node, 'is_default', False):
continue
# 检查是否有该节点的同步日志 # 检查是否有该节点的同步日志
has_node_log = any(log.process_code == node.tk_code for log in sync_logs) has_node_log = any(log.process_code == node.tk_code for log in sync_logs)
...@@ -184,9 +260,15 @@ class BlPatrol(models.Model): ...@@ -184,9 +260,15 @@ class BlPatrol(models.Model):
# 如果后续节点有日志但当前节点没有,说明漏推 # 如果后续节点有日志但当前节点没有,说明漏推
if has_next_log and not has_node_log: if has_next_log and not has_node_log:
issues.append( try:
f"{node.name}({node.tk_code})轨迹漏推" node_name = node.name or "空"
) tk_code = node.tk_code or "空"
issues.append(
f"{node_name}({tk_code})轨迹漏推"
)
except Exception as e:
_logger.warning(f"构建小包漏推问题描述失败: {str(e)}")
issues.append("节点轨迹漏推")
break break
return issues return issues
...@@ -204,19 +286,31 @@ class BlPatrol(models.Model): ...@@ -204,19 +286,31 @@ class BlPatrol(models.Model):
return issues return issues
# 检查倒叙问题 # 检查倒叙问题
issue_counter = 1
for i in range(1, len(sync_logs)): for i in range(1, len(sync_logs)):
current_log = sync_logs[i] current_log = sync_logs[i]
previous_log = sync_logs[i-1] previous_log = sync_logs[i-1]
if current_log.operate_time < previous_log.operate_time: if current_log.operate_time < previous_log.operate_time:
issues.append( try:
f"1.{bl.bl_no},出现{current_log.progress_name}({current_log.process_code})倒叙" progress_name = current_log.progress_name or "空"
) process_code = current_log.process_code or "空"
issues.append(
f"{issue_counter}、{bl.bl_no},出现{progress_name}({process_code})倒叙"
)
except Exception as e:
_logger.warning(f"构建倒叙问题描述失败: {str(e)}")
issues.append(f"{issue_counter}、{bl.bl_no},出现节点倒叙")
break break
# 检查漏推问题 # 检查漏推问题
bl_issues = self._check_bl_missing_nodes(bl, sync_logs) bl_issues = self._check_bl_missing_nodes(bl, sync_logs)
if bl_issues: if bl_issues:
# 为漏推问题添加编号
for i, issue in enumerate(bl_issues, start=len(issues) + 1):
if issue.startswith("1."):
# 替换开头的编号
bl_issues[i-1] = issue.replace("1.", f"{i}、", 1)
issues.extend(bl_issues) issues.extend(bl_issues)
return issues return issues
...@@ -240,6 +334,10 @@ class BlPatrol(models.Model): ...@@ -240,6 +334,10 @@ class BlPatrol(models.Model):
# 跳过当前节点(最后一个节点) # 跳过当前节点(最后一个节点)
if node == bl_nodes[-1]: if node == bl_nodes[-1]:
continue continue
# 跳过初始节点(is_default=True)
if getattr(node, 'is_default', False):
continue
# 检查是否有该节点的同步日志 # 检查是否有该节点的同步日志
has_node_log = any(log.process_code == node.tk_code for log in sync_logs) has_node_log = any(log.process_code == node.tk_code for log in sync_logs)
...@@ -251,9 +349,15 @@ class BlPatrol(models.Model): ...@@ -251,9 +349,15 @@ class BlPatrol(models.Model):
# 如果后续节点有日志但当前节点没有,说明漏推 # 如果后续节点有日志但当前节点没有,说明漏推
if has_next_log and not has_node_log: if has_next_log and not has_node_log:
issues.append( try:
f"1.{bl.bl_no},出现{node.name}({node.tk_code})轨迹漏推" node_name = node.name or "空"
) tk_code = node.tk_code or "空"
issues.append(
f"1.{bl.bl_no},出现{node_name}({tk_code})轨迹漏推"
)
except Exception as e:
_logger.warning(f"构建提单漏推问题描述失败: {str(e)}")
issues.append(f"1.{bl.bl_no},出现节点轨迹漏推")
break break
return issues return issues
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论