Skip to content
项目
群组
代码片段
帮助
当前项目
正在载入...
登录 / 注册
切换导航面板
H
hh_ccs
项目
项目
详情
活动
周期分析
仓库
仓库
文件
提交
分支
标签
贡献者
图表
比较
统计图
议题
0
议题
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
CI / CD
CI / CD
流水线
作业
日程
统计图
Wiki
Wiki
代码片段
代码片段
成员
成员
折叠边栏
关闭边栏
活动
图像
聊天
创建新问题
作业
提交
问题看板
Open sidebar
贺阳
hh_ccs
Commits
9aa9e4a9
提交
9aa9e4a9
authored
3月 05, 2025
作者:
贺阳
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
扫码理货推送优化
上级
7ed3b3b6
隐藏空白字符变更
内嵌
并排
正在显示
7 个修改的文件
包含
146 行增加
和
134 行删除
+146
-134
cc_bill_loading.py
ccs_base/models/cc_bill_loading.py
+2
-18
order_controller.py
ccs_connect_tiktok/controllers/order_controller.py
+12
-20
ao_tt_api_log.py
ccs_connect_tiktok/models/ao_tt_api_log.py
+0
-3
cc_bill_loading.py
ccs_connect_tiktok/models/cc_bill_loading.py
+113
-78
tt_api.py
ccs_connect_tiktok/models/tt_api.py
+0
-1
config.py
consumers/config.py
+11
-8
mail_push.py
consumers/mail_push.py
+8
-6
没有找到文件。
ccs_base/models/cc_bill_loading.py
浏览文件 @
9aa9e4a9
# 导入odoo
import
ast
import
base64
# 导入日志
import
logging
from
datetime
import
timedelta
import
pytz
import
re
import
xlrd
from
datetime
import
timedelta
,
datetime
from
odoo
import
models
,
fields
,
api
,
_
from
odoo.exceptions
import
UserError
from
pygtrans
import
Translate
# 获取日志
_logger
=
logging
.
getLogger
(
__name__
)
...
...
@@ -1068,18 +1064,6 @@ class CcBL(models.Model):
# print(wizard_obj.get_order())
wizard_obj
.
submit
()
def
try_callback_track
(
self
,
max_retries
=
3
,
ship_package_ids
=
[]):
""" 封装的重试逻辑 """
for
i
in
range
(
max_retries
):
if
not
ship_package_ids
:
is_ok
=
self
.
callback_track
()
else
:
is_ok
=
self
.
package_callback_func
(
ship_package_ids
)
if
is_ok
:
return
True
logging
.
warning
(
f
"Attempt {i + 1}/{max_retries} failed. Retrying..."
)
return
False
# 增加一个清关进度的业务对象,继承自models.Model, 用于管理业务数据.业务数据包括提单号、清关节点(业务对象)、进度日期、进度描述、更新人
class
CcProgress
(
models
.
Model
):
...
...
ccs_connect_tiktok/controllers/order_controller.py
浏览文件 @
9aa9e4a9
# -*- coding: utf-8 -*-
import
aiohttp
import
asyncio
import
certifi
import
json
import
logging
import
math
import
random
import
re
import
ssl
import
threading
from
datetime
import
datetime
,
timedelta
from
odoo
import
http
,
fields
,
exceptions
,
_
from
odoo
import
http
,
exceptions
# from odoo.addons.queue_job import job
from
odoo.http
import
request
...
...
@@ -170,21 +162,21 @@ class OrderController(http.Controller):
tally_time
=
package_item
.
get
(
'tally_time'
)
if
(
action_type
==
'tally'
and
package_item
.
get
(
'tally_state'
)
==
'checked_goods'
)
or
(
action_type
==
'handover'
and
package_item
.
get
(
'tally_state'
)
==
'handover_completed'
):
'tally_state'
)
==
'handover_completed'
):
if
package_type
==
'ship'
:
ship_packages
.
append
({
'id'
:
package_obj
.
id
,
'id'
:
[
package_obj
.
id
]
,
'tally_time'
:
tally_time
})
else
:
for
package
in
package_obj
:
ship_packages
+=
[{
'id'
:
ship_package
.
id
,
'tally_time'
:
tally_time
}
for
ship_package
in
package
.
ship_package_ids
if
(
action_type
==
'tally'
and
package
.
tally_state
==
'unprocessed_goods'
)
or
(
action_type
==
'handover'
and
package
.
tally_state
in
(
'unprocessed_goods'
,
'checked_goods'
))]
# 小包
if
(
action_type
==
'tally'
and
package
.
tally_state
==
'unprocessed_goods'
)
or
(
action_type
==
'handover'
and
package
.
tally_state
in
(
'unprocessed_goods'
,
'checked_goods'
)):
ship_packages
.
append
({
'id'
:
package
.
ship_package_ids
.
ids
,
'tally_time'
:
tally_time
})
# 小包
package_obj
.
update_big_package_info
(
action_type
=
action_type
,
tally_state
=
package_item
.
get
(
'tally_state'
),
tally_user_id
=
package_item
.
get
(
...
...
ccs_connect_tiktok/models/ao_tt_api_log.py
浏览文件 @
9aa9e4a9
# -*- coding: utf-8 -*-
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
from
datetime
import
datetime
import
logging
from
odoo
import
models
,
fields
,
api
,
_
from
odoo.exceptions
import
ValidationError
,
Warning
import
logging
...
...
ccs_connect_tiktok/models/cc_bill_loading.py
浏览文件 @
9aa9e4a9
import
aiohttp
import
asyncio
import
base64
import
certifi
import
logging
import
pytz
import
ssl
from
datetime
import
datetime
from
datetime
import
timedelta
,
datetime
from
lxml
import
etree
from
odoo
import
models
,
fields
,
api
,
tools
,
_
import
aiohttp
import
certifi
import
pytz
from
odoo
import
models
,
fields
,
api
,
_
def
get_rfc339_time
(
utc_time
=
None
):
...
...
@@ -272,12 +270,12 @@ class CcBl(models.Model):
logging
.
info
(
'package_callback_func ship_packages:
%
s'
%
len
(
ship_packages
))
is_ok
=
True
tt_api_obj
=
self
.
env
[
"ao.tt.api"
]
.
sudo
()
async
def
perform_requests
():
ssl_context
=
ssl
.
create_default_context
(
cafile
=
certifi
.
where
())
async
with
aiohttp
.
ClientSession
(
connector
=
aiohttp
.
TCPConnector
(
ssl
=
ssl_context
),
timeout
=
aiohttp
.
ClientTimeout
(
total
=
60
))
as
session
:
tasks
=
[]
logging
.
info
(
'------123'
)
for
index
,
package
in
enumerate
(
ship_packages
):
if
not
package
.
is_sync
and
package
.
state
and
package
.
state
.
tk_code
:
data
=
package
.
get_callback_track_data
()
...
...
@@ -311,7 +309,7 @@ class CcBl(models.Model):
request_id
=
response_data
[
'requestID'
]
self
.
env
[
'ao.tt.api.log'
]
.
sudo
()
.
create_api_log
(
package_order
.
tracking_no
or
''
,
''
,
data
,
0
,
request_id
,
source
=
'推出'
)
# 如果提单有小包变成了清关开始,提单状态变为清关中;如果提单所有小包的清关节点变成
“是完成节点”
,则该提单状态变成已完成
# 如果提单有小包变成了清关开始,提单状态变为清关中;如果提单所有小包的清关节点变成
"是完成节点"
,则该提单状态变成已完成
self
.
change_state_by_ship_package
()
return
is_ok
...
...
@@ -384,83 +382,120 @@ class CcBl(models.Model):
lambda
r
:
r
.
bl_no
.
replace
(
'-'
,
''
)
.
replace
(
' '
,
''
)
.
lower
()
==
processed_bl_no
)
# 提单
return
bl_obj
def
try_callback_track
(
self
,
max_retries
=
3
,
ship_package_ids
=
[]):
""" 封装的重试逻辑 """
for
i
in
range
(
max_retries
):
if
not
ship_package_ids
:
is_ok
=
self
.
callback_track
()
else
:
is_ok
=
self
.
package_callback_func
(
ship_package_ids
)
if
is_ok
:
return
True
logging
.
warning
(
f
"Attempt {i + 1}/{max_retries} failed. Retrying..."
)
return
False
def
mail_auto_push
(
self
,
mail_time
=
False
,
ship_packages
=
[],
action_type
=
'tally'
):
self
=
self
.
with_context
(
dict
(
self
.
_context
,
is_mail
=
True
))
for
item
in
self
:
try
:
if
mail_time
:
utc_time
=
datetime
.
strptime
(
mail_time
,
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
)
before_min
=
self
.
env
[
'ir.config_parameter'
]
.
sudo
()
.
get_param
(
'before_min'
)
or
10
before_utc_time
=
utc_time
-
timedelta
(
minutes
=
int
(
before_min
))
item
.
push_clear_customs_start
(
before_utc_time
)
# 尝试调用 callback_track
if
self
.
try_callback_track
():
item
.
push_clear_customs_end
(
utc_time
)
# 再次尝试调用 callback_track
if
not
self
.
try_callback_track
():
logging
.
error
(
f
"Failed to push item after {3} attempts."
)
else
:
logging
.
error
(
f
"Failed to start process for item after {3} attempts."
)
elif
ship_packages
:
ship_package_ids
=
[
ship_package_dict
[
'id'
]
for
ship_package_dict
in
ship_packages
if
ship_package_dict
[
'id'
]]
tally_state
=
'checked_goods'
if
action_type
==
'tally'
else
'handover_completed'
# 后续节点
node_obj
=
self
.
env
[
'cc.node'
]
.
sudo
()
.
search
([
(
'node_type'
,
'='
,
'package'
),
(
'tally_state'
,
'='
,
tally_state
)
# Check for both states
],
order
=
'seq asc'
)
# Order by sequence and creation date ascending
if
node_obj
:
next_minutes
=
int
(
self
.
env
[
'ir.config_parameter'
]
.
sudo
()
.
get_param
(
'next_minutes'
,
default
=
20
))
# 前序节点 理货或尾程交接之前没有生成的节点
before_node_obj
=
self
.
env
[
'cc.node'
]
.
sudo
()
.
search
([
(
'node_type'
,
'='
,
'package'
),
(
'is_must'
,
'='
,
True
),
(
'seq'
,
'<'
,
node_obj
[
0
]
.
seq
)],
order
=
'seq asc'
)
# 理货或尾程交接之前没有生成的节点
for
beforeidx
,
before_node
in
enumerate
(
before_node_obj
):
for
ship_package_dict
in
ship_packages
:
ship_package_id
=
ship_package_dict
[
'id'
]
ship_package
=
self
.
env
[
'cc.ship.package'
]
.
browse
(
ship_package_id
)
# 小包
tally_time
=
ship_package_dict
[
'tally_time'
]
before_minutes
=
before_node
.
calculate_total_interval
(
node_obj
[
0
])
operation_time
=
(
datetime
.
strptime
(
tally_time
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
-
timedelta
(
minutes
=
before_minutes
))
if
tally_time
else
fields
.
Datetime
.
now
()
-
timedelta
(
minutes
=
before_minutes
)
# 检查有没有同步过,没有同步过需要调用同步
sync_log_obj
=
ship_package
.
sync_log_ids
.
filtered
(
lambda
line
:
line
.
process_code
==
before_node
.
tk_code
)
if
not
sync_log_obj
:
# Ensure the current state is valid
ship_package
.
write
({
# try:
if
mail_time
:
utc_time
=
datetime
.
strptime
(
mail_time
,
"
%
Y-
%
m-
%
d
%
H:
%
M:
%
S"
)
before_min
=
self
.
env
[
'ir.config_parameter'
]
.
sudo
()
.
get_param
(
'before_min'
)
or
10
before_utc_time
=
utc_time
-
timedelta
(
minutes
=
int
(
before_min
))
item
.
push_clear_customs_start
(
before_utc_time
)
# 尝试调用 callback_track
if
self
.
try_callback_track
():
item
.
push_clear_customs_end
(
utc_time
)
# 再次尝试调用 callback_track
if
not
self
.
try_callback_track
():
logging
.
error
(
f
"Failed to push item after {3} attempts."
)
else
:
logging
.
error
(
f
"Failed to start process for item after {3} attempts."
)
elif
ship_packages
:
ship_package_ids
=
[
ship_package_dict
for
sublist
in
[
d
[
'id'
]
for
d
in
ship_packages
]
for
ship_package_dict
in
sublist
]
tally_state
=
'checked_goods'
if
action_type
==
'tally'
else
'handover_completed'
# 后续节点
node_obj
=
self
.
env
[
'cc.node'
]
.
sudo
()
.
search
([
(
'node_type'
,
'='
,
'package'
),
(
'tally_state'
,
'='
,
tally_state
)
# 检查理货或尾程交接的节点,根据排序进行升序
],
order
=
'seq asc'
)
if
node_obj
:
all_ship_package_obj
=
self
.
env
[
'cc.ship.package'
]
.
search
(
[(
'id'
,
'in'
,
ship_package_ids
)])
# 所有小包
# 预先获取所有同步日志 - 批量查询
all_sync_logs
=
self
.
env
[
'cc.ship.package.sync.log'
]
.
sudo
()
.
search
([
(
'package_id'
,
'in'
,
ship_package_ids
)
])
# 构建同步日志字典以加快查找
sync_log_dict
=
{}
for
log
in
all_sync_logs
:
if
log
.
package_id
.
id
not
in
sync_log_dict
:
sync_log_dict
[
log
.
package_id
.
id
]
=
set
()
sync_log_dict
[
log
.
package_id
.
id
]
.
add
(
log
.
process_code
)
# 构建ship_packages字典,用于快速查找
ship_packages_dict
=
{}
for
package
in
ship_packages
:
# 如果一个id在多个package中出现,使用最后一个package的tally_time
if
package
.
get
(
'tally_time'
):
for
single_id
in
package
[
'id'
]:
ship_packages_dict
[
single_id
]
=
package
[
'tally_time'
]
# 前序节点 理货或尾程交接之前没有生成的节点
before_node_obj
=
self
.
env
[
'cc.node'
]
.
sudo
()
.
search
([
(
'node_type'
,
'='
,
'package'
),
(
'is_must'
,
'='
,
True
),
(
'seq'
,
'<'
,
node_obj
[
0
]
.
seq
)],
order
=
'seq asc'
)
# 理货或尾程交接之前没有生成的节点
for
before_node
in
before_node_obj
:
before_minutes
=
before_node
.
calculate_total_interval
(
node_obj
[
0
])
for
package
in
all_ship_package_obj
:
package_id
=
package
.
id
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
)
if
tally_time
:
operation_time
=
(
datetime
.
strptime
(
tally_time
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
-
timedelta
(
minutes
=
before_minutes
))
if
tally_time
else
fields
.
Datetime
.
now
()
-
timedelta
(
minutes
=
before_minutes
)
package
.
write
({
'state'
:
before_node
.
id
,
'process_time'
:
operation_time
,
'state_explain'
:
before_node
.
desc
,
'is_sync'
:
True
if
before_node
.
is_default
else
False
})
self
.
try_callback_track
(
max_retries
=
2
,
ship_package_ids
=
ship_package_ids
)
# 理货或尾程交接的节点
for
index
,
node
in
enumerate
(
node_obj
):
for
ship_package_dict
in
ship_packages
:
ship_package_id
=
ship_package_dict
[
'id'
]
ship_package
=
self
.
env
[
'cc.ship.package'
]
.
browse
(
ship_package_id
)
# 小包
tally_time
=
ship_package_dict
[
'tally_time'
]
operation_time
=
(
datetime
.
strptime
(
tally_time
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
+
timedelta
(
minutes
=
next_minutes
*
index
))
if
tally_time
else
fields
.
Datetime
.
now
()
+
timedelta
(
minutes
=
next_minutes
*
index
)
# Increment time by 20 minutes for each node
state_node_obj
=
self
.
env
[
'cc.node'
]
.
sudo
()
.
search
(
[(
'node_type'
,
'='
,
'package'
),
(
'name'
,
'='
,
ship_package
.
state
.
name
)],
limit
=
1
)
if
state_node_obj
.
seq
<
node
.
seq
:
# Ensure the current state is valid
ship_package
.
write
({
'state'
:
node
.
id
,
'process_time'
:
operation_time
,
'state_explain'
:
node
.
desc
,
'is_sync'
:
True
if
node
.
is_default
else
False
})
self
.
try_callback_track
(
max_retries
=
2
,
ship_package_ids
=
ship_package_ids
)
self
.
try_callback_track
(
max_retries
=
2
,
ship_package_ids
=
ship_package_ids
)
# 理货或尾程交接的节点
# 预先获取所有状态节点
all_state_nodes
=
self
.
env
[
'cc.node'
]
.
sudo
()
.
search
([
(
'node_type'
,
'='
,
'package'
)
])
state_node_dict
=
{
node
.
name
:
node
for
node
in
all_state_nodes
}
next_minutes
=
int
(
self
.
env
[
'ir.config_parameter'
]
.
sudo
()
.
get_param
(
'next_minutes'
,
default
=
20
))
for
index
,
node
in
enumerate
(
node_obj
):
for
package
in
all_ship_package_obj
:
if
package
.
state
.
name
in
state_node_dict
:
current_state_node
=
state_node_dict
[
package
.
state
.
name
]
if
current_state_node
.
seq
<
node
.
seq
:
tally_time
=
ship_packages_dict
.
get
(
package
.
id
)
if
tally_time
:
operation_time
=
(
datetime
.
strptime
(
tally_time
,
'
%
Y-
%
m-
%
d
%
H:
%
M:
%
S'
)
+
timedelta
(
minutes
=
next_minutes
*
index
))
if
tally_time
else
fields
.
Datetime
.
now
()
+
timedelta
(
minutes
=
next_minutes
*
index
)
package
.
write
({
'state'
:
node
.
id
,
'process_time'
:
operation_time
,
'state_explain'
:
node
.
desc
,
'is_sync'
:
True
if
node
.
is_default
else
False
})
self
.
try_callback_track
(
max_retries
=
2
,
ship_package_ids
=
ship_package_ids
)
return
True
except
Exception
as
err
:
logging
.
error
(
'fetch_mail_dlv--error:
%
s'
%
str
(
err
))
#
except Exception as err:
#
logging.error('fetch_mail_dlv--error:%s' % str(err))
def
change_state_by_ship_package
(
self
):
"""
...
...
@@ -471,7 +506,7 @@ class CcBl(models.Model):
if
self
.
state
==
'draft'
and
self
.
ship_package_ids
.
filtered
(
lambda
line
:
line
.
state
.
tk_code
==
'cb_imcustoms_start'
):
self
.
ccing_func
()
# 如果提单所有小包的清关节点变成
“是完成节点”
,则该提单状态变成已完成
# 如果提单所有小包的清关节点变成
"是完成节点"
,则该提单状态变成已完成
if
all
(
line
.
state
.
is_done
for
line
in
self
.
ship_package_ids
)
and
self
.
unsync_package_count
<=
0
:
self
.
done_func
()
...
...
ccs_connect_tiktok/models/tt_api.py
浏览文件 @
9aa9e4a9
...
...
@@ -40,7 +40,6 @@ class TT(models.Model):
param_json_str
=
json
.
dumps
(
param_json
,
ensure_ascii
=
False
)
# print(param_json_str)
sign
=
self
.
make_sign
(
app_key
,
app_secret
,
version
,
timestamp
,
param_json_str
)
print
(
f
"sign={sign}"
)
# 输出生成的签名值
return
sign
...
...
consumers/config.py
浏览文件 @
9aa9e4a9
...
...
@@ -28,16 +28,19 @@ redis_options = dict(
# )
# product
# db_ip = "172.1
8.183.214
"
# db_port = "
91
69"
# db_name = "
air_order
"
# db_user = "
admin
"
# db_password = "
YHB1408ups
"
# db_ip = "172.1
04.182.220
"
# db_port = "
82
69"
# db_name = "
ccs
"
# db_user = "
YJ@yizuo.com
"
# db_password = "
yizuo123
"
#
# redis_options = dict(
# host='
172.18.183.214
',
# host='
some-redis
',
# port=32768,
# password='top123',
#
#
password='top123',
# decode_responses=True,
# db=
3
# db=
2
# )
pda_db_user
=
"pda"
pda_db_password
=
"2025"
consumers/mail_push.py
浏览文件 @
9aa9e4a9
# coding=utf-8
import
json
import
logging
import
odoorpc
import
redis
import
requests
import
time
from
datetime
import
datetime
from
requests.adapters
import
HTTPAdapter
import
config
...
...
@@ -25,6 +22,9 @@ class Order_dispose(object):
# rpc连接
self
.
odoo_db
=
odoorpc
.
ODOO
(
config
.
db_ip
,
port
=
config
.
db_port
)
self
.
odoo_db
.
login
(
config
.
db_name
,
config
.
db_user
,
config
.
db_password
)
# pda用户
self
.
pda_odoo_db
=
odoorpc
.
ODOO
(
config
.
db_ip
,
port
=
config
.
db_port
)
self
.
pda_odoo_db
.
login
(
config
.
db_name
,
config
.
pda_db_user
,
config
.
pda_db_password
)
def
order_data
(
self
,
data
):
res_data
=
[]
...
...
@@ -33,7 +33,10 @@ class Order_dispose(object):
logging
.
info
(
'mail_push_data:
%
s'
,
data
)
ship_packages
=
eval
(
data
[
'ship_packages'
])
if
data
.
get
(
'ship_packages'
)
else
[]
# 小包
action_type
=
data
.
get
(
'action_type'
)
# 类型
utc_time
=
data
.
get
(
'utc_time'
)
bl_obj
=
self
.
odoo_db
.
env
[
'cc.bl'
]
if
action_type
and
not
utc_time
:
bl_obj
=
self
.
pda_odoo_db
.
env
[
'cc.bl'
]
bl_record
=
bl_obj
.
browse
(
data
[
'id'
])
# utc_time = datetime.strptime(data['utc_time'], "%Y-%m-%d %H:%M:%S")
utc_time
=
data
.
get
(
'utc_time'
)
...
...
@@ -57,5 +60,4 @@ try:
logging
.
error
(
e
)
continue
except
Exception
as
e
:
logging
.
error
(
"登录失败"
)
logging
.
error
(
e
)
logging
.
error
(
"登录失败:
%
s"
%
e
)
编写
预览
Markdown
格式
0%
重试
或
添加新文件
添加附件
取消
您添加了
0
人
到此讨论。请谨慎行事。
请先完成此评论的编辑!
取消
请
注册
或者
登录
后发表评论