提交 007e8bae authored 作者: 伍姿英's avatar 伍姿英

Merge branch 'release/V2.5.1'

......@@ -60,7 +60,7 @@ class ExportBlAndPackageXlsx(http.Controller):
sheet1.write(good_index, 26, good_item.item_name_en or '') # ITEM DESCRIPTION
sheet1.write(good_index, 27, good_item.export_hs_code or '') # ITEM HS CODE
sheet1.write(good_index, 28, good_item.quantity) # ITEM QUANTITY
sheet1.write(good_index, 29, good_item.quantity_unit or '') # UNIT VALUE
sheet1.write(good_index, 29, good_item.quantity_unit or '') # UNITS
sheet1.write(good_index, 30, good_item.item_total_price) # TOTAL VALUE
sheet1.write(good_index, 31, good_item.item_vat or '') # VAT
sheet1.write(good_index, 32, '') # SKU NUMBER
......@@ -112,7 +112,7 @@ class ExportBlAndPackageXlsx(http.Controller):
sheet1.write(index, 26, u'ITEM DESCRIPTION', font_style) # ITEM DESCRIPTION
sheet1.write(index, 27, u'ITEM HS CODE', font_style) # ITEM HS CODE
sheet1.write(index, 28, u'ITEM QUANTITY', font_style) # ITEM QUANTITY
sheet1.write(index, 29, u'UNIT VALUE', font_style) # UNIT VALUE
sheet1.write(index, 29, u'UNITS', font_style) # UNITS
sheet1.write(index, 30, u'TOTAL VALUE', font_style) # TOTAL VALUE
sheet1.write(index, 31, u'VAT', font_style) # VAT
sheet1.write(index, 32, u'ONLINE SELLING PLACE', font_style) # ONLINE SELLING PLACE
......
# 导入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):
......
# -*- 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(
......
# -*- 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
......
import aiohttp
import asyncio
import base64
import certifi
import json
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, _
from odoo.exceptions import ValidationError, Warning
import aiohttp
import certifi
import pytz
from odoo import models, fields, api, _
def get_rfc339_time(utc_time=None):
......@@ -280,7 +276,6 @@ class CcBl(models.Model):
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()
......@@ -298,6 +293,7 @@ class CcBl(models.Model):
package_order = self.env['cc.ship.package'].sudo().browse(package_id)
if response_data['code'] != 0:
package_order.is_sync = False
self._cr.commit() # 提交事务
error_msg = response_data['msg']
request_id = response_data['requestID']
code = response_data['code']
......@@ -308,12 +304,15 @@ class CcBl(models.Model):
else:
# 回传成功
package_order.is_sync = True
self._cr.commit() # 提交事务
self.env['cc.ship.package.sync.log'].sudo().create_sync_log(
package_order.id, 'Tiktok', package_order.state.tk_code, package_order.state_explain,
package_order.process_time.strftime('%Y-%m-%d %H:%M:%S'))
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
def deal_ship_package_state(self):
......@@ -385,86 +384,198 @@ 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({
'state': before_node.id,
'process_time': operation_time,
'state_explain': before_node.desc,
'is_sync': True if before_node.is_default else False
})
# 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:
print('before_node:%s' % before_node.name)
before_minutes = before_node.calculate_total_interval(node_obj[0])
# 准备批量更新数据
update_data = []
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)
update_data.append((
package_id,
before_node.id,
operation_time,
before_node.desc,
True if before_node.is_default else False
))
if update_data:
# 构建批量更新SQL
values_str = ','.join(
self.env.cr.mogrify("(%s,%s,%s,%s,%s)", row).decode('utf-8') for row in update_data)
sql = """
UPDATE cc_ship_package AS t SET
state = c.state,
process_time = c.process_time,
state_explain = c.state_explain,
is_sync = c.is_sync
FROM (VALUES
{}
) AS c(id, state, process_time, state_explain, is_sync)
WHERE t.id = c.id
""".format(values_str)
self.env.cr.execute(sql)
self._cr.commit() # 提交事务
# # 更新提单的未同步小包数量
# sql = """
# UPDATE cc_bl AS bl SET
# unsync_package_count = (
# SELECT COUNT(*)
# FROM cc_ship_package sp
# WHERE sp.bl_id = bl.id
# AND sp.is_sync = false
# )
# WHERE bl.id = %s
# """
# self.env.cr.execute(sql, (item.id,))
# self._cr.commit() # 提交事务
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
})
# 理货或尾程交接的节点
# 预先获取所有状态节点
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):
print('node:%s' % node.name)
update_data = []
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)
update_data.append((
package.id,
node.id,
operation_time,
node.desc,
True if node.is_default else False
))
print('update_data:%s' % update_data)
if update_data:
print('11111111111')
# 构建批量更新SQL
values_str = ','.join(
self.env.cr.mogrify("(%s,%s,%s,%s,%s)", row).decode('utf-8') for row in update_data)
sql = """
UPDATE cc_ship_package AS t SET
state = c.state,
process_time = c.process_time,
state_explain = c.state_explain,
is_sync = c.is_sync
FROM (VALUES
{}
) AS c(id, state, process_time, state_explain, is_sync)
WHERE t.id = c.id
""".format(values_str)
self.env.cr.execute(sql)
self._cr.commit() # 提交事务
# # 更新提单的未同步小包数量
# sql = """UPDATE cc_bl AS bl SET unsync_package_count = ( SELECT COUNT(*) FROM cc_ship_package sp WHERE sp.bl_id = bl.id AND sp.is_sync = false) WHERE bl.id = %s """
# self.env.cr.execute(sql, (item.id,))
# self._cr.commit() # 提交事务
print('222222')
self.try_callback_track(max_retries=2, ship_package_ids=ship_package_ids)
if self.state == 'draft' and self.ship_package_ids.filtered(
lambda line: line.state.tk_code == 'cb_imcustoms_start'):
self.ccing_func()
print('33333')
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):
"""
根据小包的状态修改提单的状态
:return:
"""
# 如果提单有小包变成了清关开始,提单状态变为清关中
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()
class CcBigPackage(models.Model):
......
......@@ -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
......
......@@ -157,13 +157,11 @@ class BatchInputShipPackageStatusWizard(models.TransientModel):
bl_obj.message_post(body=_('[%s]%sUpdate to[%s]%s') % (
self.current_status.tk_code or '', self.current_status.name or '', self.update_status.tk_code or '',
self.update_status.name or ''), author_id=public_user.id,
email_from=public_user.display_name)
email_from=public_user.display_name)
else:
bl_obj.message_post(body=_('[%s]%sUpdate to[%s]%s') % (
self.current_status.tk_code or '', self.current_status.name or '', self.update_status.tk_code or '',
self.update_status.name or ''))
# 如果提单有小包变成了清关开始,提单状态变为清关中
if bl_obj.state == 'draft' and bl_obj.ship_package_ids.filtered(
lambda line: line.state.tk_code == 'cb_imcustoms_start'):
bl_obj.ccing_func()
# 如果提单有小包变成了清关开始,提单状态变为清关中;如果提单所有小包的清关节点变成“是完成节点”,则该提单状态变成已完成
bl_obj.change_state_by_ship_package()
return obj
......@@ -28,16 +28,19 @@ redis_options = dict(
# )
# product
# db_ip = "172.18.183.214"
# db_port = "9169"
# db_name = "air_order"
# db_user = "admin"
# db_password = "YHB1408ups"
# db_ip = "172.104.182.220"
# db_port = "8269"
# 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"
# 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 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论