提交 8af2ea18 authored 作者: 伍姿英's avatar 伍姿英

Merge branch 'release/3.9.0'

......@@ -6,8 +6,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-10-31 02:15+0000\n"
"PO-Revision-Date: 2025-10-31 10:16+0800\n"
"POT-Creation-Date: 2026-02-06 06:30+0000\n"
"PO-Revision-Date: 2026-02-06 14:32+0800\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: zh_CN\n"
......@@ -57,7 +57,7 @@ msgstr "附件"
#. module: ccs_connect_tiktok
#: model:ir.model,name:ccs_connect_tiktok.model_batch_get_pod_info_wizard
msgid "Batch Get POD Info Wizard"
msgstr "批量获取尾程POD向导"
msgstr "批量获取POD向导"
#. module: ccs_connect_tiktok
#: model:ir.actions.server,name:ccs_connect_tiktok.action_batch_sync_bl_status
......@@ -287,6 +287,11 @@ msgstr ""
msgid "Is Bill Of Loading Sync"
msgstr "关务提单状态是否同步"
#. module: ccs_connect_tiktok
#: model:ir.model.fields,field_description:ccs_connect_tiktok.field_cc_node__is_patrol_node
msgid "Is Patrol Node"
msgstr "是巡查节点"
#. module: ccs_connect_tiktok
#: model:ir.model.fields,field_description:ccs_connect_tiktok.field_cc_ship_package__is_sync
#: model_terms:ir.ui.view,arch_db:ccs_connect_tiktok.form_cc_bl_view_inherit
......@@ -867,6 +872,13 @@ msgstr ""
msgid "推出"
msgstr ""
#. module: ccs_connect_tiktok
#. odoo-python
#: code:addons/ccs_connect_tiktok/wizard/batch_get_pod_info_wizard.py:0
#, python-format
msgid "提单 %s 没有提取到时间信息,请检查提单是否正确"
msgstr ""
#. module: ccs_connect_tiktok
#: model:ir.model.fields,field_description:ccs_connect_tiktok.field_bl_patrol__bl_issues
#: model_terms:ir.ui.view,arch_db:ccs_connect_tiktok.view_bl_patrol_form
......
......@@ -375,6 +375,7 @@ class CcBl(models.Model):
:param user_obj:
:return:
"""
logging.info(f"package_state_obj: {package_state_obj}")
# 根据小包的状态找到对应的提单关务状态
state_obj = self.env['cc.node'].search([('package_state', '=', package_state_obj.id)], limit=1)
for bl in self:
......@@ -390,25 +391,114 @@ class CcBl(models.Model):
is_ok = True
for before_node in before_node_obj:
if not bl.bl_sync_log_ids.filtered(lambda r: r.process_code == before_node.tk_code):
# 修改关务提单状态
bl.customs_clearance_status = before_node.id
# 操作时间根据设置的前序节点间距时间取值
before_minutes = before_node.calculate_total_interval(state_obj)
bl.process_time = datetime.strptime(str(operate_time), '%Y-%m-%d %H:%M:%S') - timedelta(
candidate_time = datetime.strptime(str(operate_time),
'%Y-%m-%d %H:%M:%S') - timedelta(
minutes=before_minutes)
prev_nodes = before_node.get_before_node(node_type='bl')
if prev_nodes:
prev_codes = prev_nodes.mapped('tk_code')
prev_logs = bl.bl_sync_log_ids.filtered(
lambda r: r.process_code in prev_codes and r.operate_time)
if prev_logs:
latest_prev_time = max(prev_logs.mapped('operate_time'))
logging.info(f"latest_prev_time: {latest_prev_time}")
if candidate_time < latest_prev_time:
remark = (
f"自动补写提单前序关务节点被拦截,节点:{before_node.desc or before_node.name},"
f"候选时间:{candidate_time.strftime('%Y-%m-%d %H:%M:%S')},"
f"前序节点最新时间:{latest_prev_time.strftime('%Y-%m-%d %H:%M:%S')}。"
f"存在时间倒挂风险,请核查。"
)
bl.message_post(body=remark)
# continue
is_ok = False
break
next_nodes = self.env['cc.node'].sudo().search([
('node_type', '=', 'bl'),
('is_must', '=', True),
('seq', '>', before_node.seq),
])
if next_nodes:
next_codes = next_nodes.mapped('tk_code')
next_logs = bl.bl_sync_log_ids.filtered(
lambda r: r.process_code in next_codes and r.operate_time)
if next_logs:
earliest_next_time = min(next_logs.mapped('operate_time'))
logging.info(
f"earliest_next_time: {earliest_next_time}, candidate_time: {candidate_time}")
if candidate_time > earliest_next_time:
remark = (
f"自动补写提单前序关务节点被拦截,节点:{before_node.desc or before_node.name},"
f"候选时间:{candidate_time.strftime('%Y-%m-%d %H:%M:%S')},"
f"后续节点最早时间:{earliest_next_time.strftime('%Y-%m-%d %H:%M:%S')}。"
f"存在时间倒挂风险,请核查。"
)
bl.message_post(body=remark)
is_ok = False
break
if not is_ok:
break
bl.customs_clearance_status = before_node.id
bl.process_time = candidate_time
bl.is_bl_sync = before_node.node_is_sync()
self._cr.commit()
# 调用同步关务提单状态
is_ok = bl.callback_track_bl(user_obj)
if not is_ok:
break
if is_ok:
bl.customs_clearance_status = state_obj.id
bl.process_time = operate_time
bl.is_bl_sync = state_obj.node_is_sync()
self._cr.commit()
# 调用同步提单状态
bl.callback_track_bl(user_obj)
candidate_time = operate_time
prev_nodes = state_obj.get_before_node(node_type='bl')
allow_push = True
block_reason = ""
if prev_nodes:
prev_codes = prev_nodes.mapped('tk_code')
prev_logs = bl.bl_sync_log_ids.filtered(
lambda r: r.process_code in prev_codes and r.operate_time)
if prev_logs:
latest_prev_time = max(prev_logs.mapped('operate_time'))
if candidate_time < latest_prev_time:
allow_push = False
block_reason = (
f"候选时间早于前序节点最新时间(候选时间:"
f"{candidate_time.strftime('%Y-%m-%d %H:%M:%S')},前序最新时间:"
f"{latest_prev_time.strftime('%Y-%m-%d %H:%M:%S')})"
)
if allow_push:
next_nodes = self.env['cc.node'].sudo().search([
('node_type', '=', 'bl'),
('is_must', '=', True),
('seq', '>', state_obj.seq),
])
logging.info(f"next_nodes: {next_nodes}")
if next_nodes:
next_codes = next_nodes.mapped('tk_code')
next_logs = bl.bl_sync_log_ids.filtered(
lambda r: r.process_code in next_codes and r.operate_time)
logging.info(f"next_logs: {next_logs}")
if next_logs:
earliest_next_time = min(next_logs.mapped('operate_time'))
if candidate_time > earliest_next_time:
allow_push = False
block_reason = (
f"候选时间晚于后续节点最早时间(候选时间:"
f"{candidate_time.strftime('%Y-%m-%d %H:%M:%S')},后续最早时间:"
f"{earliest_next_time.strftime('%Y-%m-%d %H:%M:%S')})"
)
logging.info(f"allow_push: {allow_push}")
if allow_push:
logging.info(f"state_obj: {state_obj.tk_code}")
bl.customs_clearance_status = state_obj.id
bl.process_time = candidate_time
bl.is_bl_sync = state_obj.node_is_sync()
self._cr.commit()
bl.callback_track_bl(user_obj)
elif block_reason:
remark = (
f"自动补写提单关务节点被拦截,节点:{state_obj.desc or state_obj.name},"
f"{block_reason}。存在时间倒挂风险,请核查。"
)
bl.message_post(body=remark)
# 如果提单有小包变成了清关开始,提单状态变为清关中;如果提单所有小包的清关节点变成"是完成节点",则该提单状态变成已完成
bl.change_state_by_ship_package()
......@@ -549,7 +639,7 @@ class CcBl(models.Model):
logs_by_process[log.process_code] = log
# 方法1: 根据节点的seq进行排序(推荐)
sync_logs = []
bl_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('is_must', '=', True)],
bl_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('is_patrol_node', '=', True)],
order='seq')
if bl_nodes:
for node in bl_nodes:
......@@ -646,7 +736,7 @@ class CcBl(models.Model):
"""
issues = []
# 获取所有小包节点,按顺序排序
package_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('is_must', '=', True)],
package_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'package'), ('is_patrol_node', '=', True)],
order='seq')
if not package_nodes:
return issues
......@@ -696,7 +786,7 @@ class CcBl(models.Model):
# 根据节点的seq进行排序
sync_logs = []
# 获取所有提单节点,按业务顺序排序
bl_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'bl'), ('is_must', '=', True)], order='seq')
bl_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'bl'), ('is_patrol_node', '=', True)], order='seq')
if bl_nodes:
for node in bl_nodes:
if node.tk_code in logs_by_bl_process.keys():
......@@ -753,7 +843,7 @@ class CcBl(models.Model):
"""
issues = []
# 获取所有提单节点,按顺序排序
bl_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'bl'), ('is_must', '=', True)], order='seq')
bl_nodes = self.env['cc.node'].sudo().search([('node_type', '=', 'bl'), ('is_patrol_node', '=', True)], order='seq')
if not bl_nodes:
return issues
# 检查每个节点是否有对应的同步日志
......@@ -1217,6 +1307,7 @@ class CcBl(models.Model):
if self.ship_package_ids:
# 检查所有小包状态是否一致
states = set(self.ship_package_ids.mapped('state.id'))
logging.info(f"states: {states}")
if len(states) == 1:
self.change_customs_state_by_ship_package(self.ship_package_ids[0].state, user_obj=user_obj)
else:
......@@ -1292,12 +1383,15 @@ class CcBl(models.Model):
# 合并前序节点和当前节点,去重
before_node_obj = before_node_obj | node_obj[0]
# 理货或尾程交接之前没有生成的节点
for before_node in before_node_obj:
for idx, before_node in enumerate(before_node_obj):
before_minutes = before_node.calculate_total_interval(node_obj[0])
# 准备批量更新数据
update_data = []
for package in all_ship_package_obj:
package_id = package.id
# 后续节点只处理上一节点同步成功(is_sync=True)的小包
if idx > 0 and not package.is_sync:
continue
if package_id not in sync_log_dict or before_node.tk_code not in sync_log_dict.get(
package_id, set()):
tally_time = ship_packages_dict.get(package_id)
......@@ -1348,6 +1442,9 @@ class CcBl(models.Model):
for index, node in enumerate(node_obj):
update_data = []
for package in all_ship_package_obj:
# 只有上一节点同步成功的小包才生成后续节点
if not package.is_sync:
continue
if package.state.name in state_node_dict:
current_state_node = state_node_dict[package.state.name]
if current_state_node.seq < node.seq:
......
......@@ -11,6 +11,7 @@ class CCNode(models.Model):
tk_code = fields.Char('TK Code', help='TK Code')
interval_minutes = fields.Integer('Predecessor Node Interval (Minutes)', default=20,
help='Default interval time between predecessor nodes in minutes.') # 前序节点间隔时间,默认20分钟
is_patrol_node = fields.Boolean('Is Patrol Node', default=False)
def get_before_node(self, node_type='package'):
"""
......
......@@ -2,7 +2,7 @@
<odoo>
<data>
<!-- # 继承节点的tree视图,增加tt_code字段在列表中-->
<!-- # 继承节点的tree视图,增加tt_code字段在列表中-->
<record model="ir.ui.view" id="tree_cc_node_view_inherit">
<field name="name">tree.cc.node.view</field>
<field name="model">cc.node</field>
......@@ -16,6 +16,9 @@
<field name="interval_minutes"/>
</field>
<field name="is_must" position="after">
<field name="is_patrol_node"/>
</field>
</field>
</record>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论