提交 2656a7c1 authored 作者: 贺阳's avatar 贺阳

提单状态

上级 44d2fe95
......@@ -670,6 +670,12 @@ class CcBL(models.Model):
# 通关文件, 关联附件对象(类型限定为image和PDF)
cc_attachment_ids = fields.One2many('cc.clearance.file', 'bl_id', string='Clearance Files')
# 提单上新增字段:关务提单状态,用英文:关联节点的配置(cc.node),节点类型过滤提单的节点名称。
customs_clearance_status = fields.Many2one('cc.node', string='Customs Clearance Status',
domain=[('node_type', '=', 'bl')])
# 增加提单状态操作时间
process_time = fields.Datetime(string='Process Time')
# 增加一个can_cancel的方法,用于检查提单当前是否可以取消,返回True表示可以取消, False表示不可以取消,同时返回取消的原因
def check_cancel(self):
if self.is_cancel:
......
......@@ -48,3 +48,8 @@ class CcNode(models.Model):
('checked_goods', 'Checked goods'),
('handover_completed', 'Handover Completed')
], default='', string='Corresponding to the status of the big package', index=True) # 对应大包状态 未理货/已理货/尾程交接
# 新增字段:对应小包状态。只有类型为提单上才可填写。可选已配置节点类型为小包的节点。单选;
package_state = fields.Many2one('cc.node', string='Corresponding to the status of the package',domain="[('node_type','=','package')]", index=True) # 对应小包状态
......@@ -50,8 +50,12 @@
<!-- # 为action_batch_input_ship_package_wizard添加一个按钮, 上下文中添加bl_id-->
<button name="%(action_batch_input_ship_package_wizard)d" type="action" class="oe_highlight"
string="Update Ship Package Status"
context="{'default_bl_id': active_id, 'active_id': id}"/>
context="{'default_bl_id': active_id, 'active_id': id,'default_action_type':'小包'}"/>
<button name="%(action_batch_input_ship_package_wizard)d" type="action" class="oe_highlight"
string="Update BL Status"
context="{'active_id': id,'default_action_type':'提单'}"/>
<field name="state" widget="statusbar" options="{'clickable': '1'}"/>
</header>
<sheet>
......
......@@ -82,12 +82,14 @@ class BatchInputShipPackageStatusWizard(models.TransientModel):
state_explain = fields.Text('State Explain', help='State Explain')
node_exception_reason_id = fields.Many2one('cc.node.exception.reason', 'Exception Reason',
domain="[('code_id', '=', update_status)]")
action_type = fields.Char(string='Action Type', default='小包')
# 批量更新小包状态
def submit(self):
# 确认数据
if not self.is_ok:
raise ValidationError('Please confirm that the above data is correct.') # 请确认以上数据正确
if self.action_type == '小包':
parcels = self.get_process_package()
if not parcels:
......
......@@ -24,6 +24,7 @@
'views/config_settings_views.xml',
# 'views/flight_order_view.xml',
'views/cc_ship_package_sync_log_view.xml',
'views/cc_bl_sync_log_view.xml',
'views/ao_tt_api_log_view.xml',
'views/cc_node_view.xml',
'views/cc_ship_package_view.xml',
......
# -*- coding: utf-8 -*-
import asyncio
import logging
import ssl
......@@ -251,8 +252,103 @@ class CcBl(models.Model):
else:
record.unsync_package_count = 0
# 计算提单状态操作时间
@api.depends('bl_sync_log_ids')
def _compute_process_time(self):
for bl in self:
if bl.bl_sync_log_ids:
bl.process_time = bl.bl_sync_log_ids.mapped('operate_time').sorted(reverse=True)[0]
else:
bl.process_time = False
# 增加未同步小包数量字段
unsync_package_count = fields.Integer('Unsync Package Count', compute='_compute_unsync_package_count', store=True)
is_bl_sync = fields.Boolean('Is BL Synchronized', default=False)
# 关联提单同步日志
bl_sync_log_ids = fields.One2many('cc.bl.sync.log', 'bl_id', string='BL Sync Logs')
# 增加提单状态操作时间:取最新一条提单节点同步信息的操作时间
process_time = fields.Datetime(string='Process Time', compute='_compute_process_time', store=True)
# =============同步提单状态==================================
# 增加同步提单状态的方法
def action_sync_bl_status(self):
self.callback_track_bl()
# 定义一个方法, 获取提单,并回传提单状态
def callback_track_bl(self):
is_ok = True
for item in self:
is_ok = item.bl_callback_func(item.ids)
return is_ok
def bl_callback_func(self, bl_ids):
"""
同步提单状态
"""
bls = self.env['cc.bl'].search([('id', 'in', bl_ids), ('is_bl_sync', '=', False)])
logging.info('bl_callback_func bls:%s' % len(bls))
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 = []
for index, bl in enumerate(bls):
if not bl.is_bl_sync and bl.state and bl.state.tk_code:
data = bl.get_bl_callback_track_data()
tasks.append(tt_api_obj.async_bl_callback_track(session, data, bl.id))
responses = await asyncio.gather(*tasks)
return responses
# 在 Odoo 中运行异步任务
responses = asyncio.run(perform_requests())
for response_item in responses:
response_data = response_item[0]
logging.info('bl response_data response:%s' % response_data)
data = response_item[1]
bl_id = response_item[2]
bl_order = self.env['cc.bl'].sudo().browse(bl_id)
if response_data['code'] != 0:
bl_order.is_bl_sync = False
self._cr.commit() # 提交事务
error_msg = response_data['msg']
request_id = response_data['requestID']
code = response_data['code']
self.env['ao.tt.api.log'].sudo().create_api_log(
bl_order.bl_no or '', '提单状态回传:' + error_msg, data, code, request_id,
source='推出')
is_ok = False
else:
# 回传成功
bl_order.is_bl_sync = True
self._cr.commit() # 提交事务
self.env['cc.bl.sync.log'].sudo().create_sync_log(
bl_order.id, 'Tiktok', bl_order.state.tk_code, bl_order.state.name, bl_order.state_explain,
bl_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(
bl_order.bl_no or '', '', data, 0, request_id, source='推出')
return is_ok
def get_bl_callback_track_data(self):
"""
获取提单回传数据
"""
return {
"master_waybill_no": self.bl_no or '', # 主提运单号
"customs_waybill_no": self.customs_bl_no or '', # 关务提单号取海关装货单号
"track_detail": [
{
"operate_time": get_utc_time(self.process_time), # 事件发⽣时间,RFC3339格式(实操时间)
"waybill_status_code": self.state.tk_code, # 提单关务状态编码
}
]
}
# =============同步小包状态==================================
# 定义一个方法, 获取提单下的所有未同步的小包,并回传小包状态
def callback_track(self):
......@@ -399,7 +495,7 @@ class CcBl(models.Model):
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:
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
......@@ -461,7 +557,8 @@ class CcBl(models.Model):
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(
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((
......@@ -532,9 +629,7 @@ class CcBl(models.Model):
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)
......@@ -556,13 +651,11 @@ class CcBl(models.Model):
# 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)
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):
"""
......@@ -578,6 +671,46 @@ class CcBl(models.Model):
self.done_func()
# 提单节点同步日志
class CcBlSyncLog(models.Model):
_name = 'cc.bl.sync.log'
_description = 'CC Bl Sync Log'
# 定义模型字段
# 提单对象
bl_id = fields.Many2one('cc.bl', 'Bill of Loading', required=True)
# 同步时间
sync_time = fields.Datetime('Sync Time', default=fields.Datetime.now)
# 增加接口客户
api_customer = fields.Char('Api Customer')
# 操作状态
process_code = fields.Char('TK Process Code')
# 加一个进度名称
progress_name = fields.Char('Progress Name')
# 操作时间
operate_time = fields.Datetime('Operate Time', default=fields.Datetime.now)
# 操作备注
operate_remark = fields.Text('Operate Remark')
# 同步操作人
operate_user = fields.Many2one('res.users', 'Operate User', default=lambda self: self.env.user)
# 添加一个新增日志的方法,传入小包ID,API客户,操作状态,操作备注,操作时间
@api.model
def create_sync_log(self, package_id, api_customer, process_code, progress_name, operate_remark, operate_time):
vals = {
'package_id': package_id,
'api_customer': api_customer,
'process_code': process_code,
'progress_name': progress_name,
'operate_remark': operate_remark,
'operate_time': operate_time
}
if self._context.get('is_mail'):
public_user = self.env.ref('base.public_user')
vals['operate_user'] = public_user.id
return self.create(vals)
class CcBigPackage(models.Model):
# 模型名称
_inherit = 'cc.big.package'
......
......@@ -44,7 +44,7 @@ class TT(models.Model):
def callback_track(self, push_data):
"""包裹轨迹回传"""
"""包裹轨迹/提单状态回传"""
url = '/logistics/provider/cross_border/callback_track?country=GB'
# cb_excustoms_finished 出口清关完毕
# cb_transport_assigned 干线揽收
......@@ -66,7 +66,7 @@ class TT(models.Model):
def mwb_status_update(self, push_data):
"""清关提单状态回传"""
url = 'logistics/provider/customs/mwb_status_update'
url = 'logistics/provider/customs/mwb_status_update?country=GB'
timestamp = int(time.time())
sign = self.generate_sign(timestamp, push_data)
response = self.get_response(url, sign, timestamp, push_data)
......@@ -126,20 +126,20 @@ class TT(models.Model):
'app_key': app_key
}
request_url = tt_url + url
logging.info('request_url: %s' % request_url)
logging.info('request_data: %s' % parameter)
# logging.info('request_url: %s' % request_url)
# logging.info('request_data: %s' % parameter)
for i in range(3): # 尝试最多3次
try:
async with session.post(request_url, headers=headers, data=parameter) as response:
response_data = await response.json()
logging.info('response: %s', response_data)
# logging.info('response: %s', response_data)
# print(response.json())
return response_data
except Exception as e:
if i < 2: # 如果不是最后一次尝试,等待后重试
await asyncio.sleep(2 ** i) # 指数退避策略
else:
logging.warning('request error:%s' % str(e))
# logging.warning('request error:%s' % str(e))
return {'code': 500, 'requestID': 'request error timeout', 'msg': '超时,请重试'} # 如果重试次数用尽,抛出异常
async def async_callback_track_callback(self, session, push_data, package_id):
......@@ -157,3 +157,17 @@ class TT(models.Model):
"""异步调用推送接口"""
# async with semaphore:
return await self.async_callback_track_callback(session, data, package_id)
async def async_bl_callback_track_callback(self, session, push_data, package_id):
"""提单状态回传"""
url = '/logistics/provider/customs/mwb_status_update?country=GB'
timestamp = int(time.time())
sign = self.generate_sign(timestamp, push_data)
response = await self.async_get_response(session, url, sign, timestamp, push_data)
logging.info('bl_callback_track response:%s' % response)
return response, push_data, package_id
async def async_bl_callback_track(self, session, data, bl_id):
"""异步调用提单推送接口"""
# async with semaphore:
return await self.async_bl_callback_track_callback(session, data, bl_id)
......@@ -7,3 +7,10 @@ access_cc_ship_package_sync_log_base.group_erp_manager,cc_ship_package_sync_log
access_cc_ship_package_sync_log_ccs_base.group_clearance_of_customs_manager,cc_ship_package_sync_log ccs_base.group_clearance_of_customs_manager,ccs_connect_tiktok.model_cc_ship_package_sync_log,ccs_base.group_clearance_of_customs_manager,1,0,0,0
access_cc_ship_package_sync_log_ccs_base.group_clearance_of_customs_user,cc_ship_package_sync_log ccs_base.group_clearance_of_customs_user,ccs_connect_tiktok.model_cc_ship_package_sync_log,ccs_base.group_clearance_of_customs_user,1,0,0,0
access_cc_bl_sync_log_base.group_user,cc_bl_sync_log base.group_user,ccs_connect_tiktok.model_cc_bl_sync_log,base.group_user,1,0,0,0
access_cc_bl_sync_log_base.group_erp_manager,cc_bl_sync_log base.group_erp_manager,ccs_connect_tiktok.model_cc_bl_sync_log,base.group_erp_manager,1,1,1,1
access_cc_bl_sync_log_ccs_base.group_clearance_of_customs_manager,cc_bl_sync_log ccs_base.group_clearance_of_customs_manager,ccs_connect_tiktok.model_cc_bl_sync_log,ccs_base.group_clearance_of_customs_manager,1,0,0,0
access_cc_bl_sync_log_ccs_base.group_clearance_of_customs_user,cc_bl_sync_log ccs_base.group_clearance_of_customs_user,ccs_connect_tiktok.model_cc_bl_sync_log,ccs_base.group_clearance_of_customs_user,1,0,0,0
<?xml version="1.0" encoding="utf-8"?>
<odoo>
# ---------- CC Bl Sync Log ------------
<record model="ir.ui.view" id="tree_cc_bl_sync_log_view">
<field name="name">tree.cc.bl.sync.log</field>
<field name="model">cc.bl.sync.log</field>
<field name="arch" type="xml">
<tree string="CC Bl Sync Log">
<field optional="show" name="bl_id" string="Bill of Loading"/>
<field optional="show" name="api_customer" string="Api Customer"/>
<field optional="show" name="process_code" string="TK Process Code"/>
<field optional="show" name="progress_name" string="Progress Name"/>
<field optional="show" name="operate_time" string="Operate Time"/>
<field optional="show" name="operate_user" string="Operate User"/>
<field optional="show" name="sync_time" string="Sync Time"/>
</tree>
</field>
</record>
<record model="ir.ui.view" id="form_cc_bl_sync_log_view">
<field name="name">form.cc.bl.sync.log</field>
<field name="model">cc.bl.sync.log</field>
<field name="arch" type="xml">
<form string="CC Bl Sync Log">
<sheet>
<group>
<group>
<field name="bl_id" string="Bill of Loading"/>
<field name="api_customer" string="Api Customer"/>
<field name="process_code" string="TK Process Code"/>
<field name="progress_name" string="Progress Name"/>
<field name="operate_time" string="Operate Time"/>
<field name="operate_user" string="Operate User"/>
<field name="sync_time" string="Sync Time"/>
</group>
<group>
</group>
</group>
<notebook>
<page string="Operate Remark">
<field name="operate_remark" string="Operate Remark"/>
</page>
</notebook>
</sheet>
</form>
</field>
</record>
<record model="ir.ui.view" id="search_cc_bl_sync_log_view">
<field name="name">search.cc.bl.sync.log</field>
<field name="model">cc.bl.sync.log</field>
<field name="arch" type="xml">
<search string="CC Bl Sync Log">
<field name="bl_id" string="Bill of Loading"/>
<field name="api_customer" string="Api Customer"/>
<field name="process_code" string="TK Process Code"/>
<field name="operate_time" string="Operate Time"/>
<field name="operate_user" string="Operate User"/>
<field name="sync_time" string="Sync Time"/>
<separator/>
<filter name="filter_operate_time" string="Operate Time" date="operate_time"/>
<filter name="filter_sync_time" string="Sync Time" date="sync_time"/>
<separator/>
<group expand="0" string="Group By">
<filter domain="[]" name="groupby_bl_id" string="Bill of Loading"
context="{'group_by': 'bl_id'}"/>
<filter domain="[]" name="groupby_operate_user" string="Operate User"
context="{'group_by': 'operate_user'}"/>
</group>
</search>
</field>
</record>
<record model="ir.actions.act_window" id="action_cc_bl_sync_log">
<field name="name">CC Bl Sync Log</field>
<field name="res_model">cc.bl.sync.log</field>
<field name="view_mode">tree</field>
<field name="domain">[]</field>
<field name="context">{}</field>
<field name="help" type="html">
<p class="o_view_nocontent_smiling_face">
[CC Bl Sync Log] Not yet! Click the Create button in the top left corner and the sofa is yours!
</p>
<p>
</p>
</field>
</record>
</odoo>
\ No newline at end of file
......@@ -24,6 +24,8 @@
<header position="inside">
<button name="callback_track" string="Sync Package Status" type="object"/>
<button name="batch_action_sync" string="Sync CC Attachment" type="object"/>
<!--增加同步提单状态的按钮-->
<button name="action_sync_bl_status" string="Sync Bl Status" type="object"/>
</header>
<button name="action_show_ship_package" position="replace">
......@@ -45,48 +47,9 @@
</div>
</button>
</button>
</field>
</record>
<!-- # 继承ccs_base模块的cc_ship_package_view.xml视图,增加is_sync字段在列表中-->
<record model="ir.ui.view" id="tree_cc_ship_package_view_inherit">
<field name="name">tree_cc_ship_package_view_inherit</field>
<field name="model">cc.ship.package</field>
<field name="inherit_id" ref="ccs_base.tree_cc_ship_package_view"/>
<field name="arch" type="xml">
<field name="state" position="after">
<field name="is_sync"/>
</field>
<tree position="attributes">
<attribute name="decoration-danger">is_sync == False</attribute>
</tree>
</field>
</record>
<!-- # 继承ccs_base模块的search_cc_ship_package_view视图,装置加未同步的筛选条件-->
<record model="ir.ui.view" id="search_cc_ship_package_view_inherit">
<field name="name">search_cc_ship_package_view_inherit</field>
<field name="model">cc.ship.package</field>
<field name="inherit_id" ref="ccs_base.search_cc_ship_package_view"/>
<field name="arch" type="xml">
<search position="inside">
<filter string="Not Sync" name="filter_is_sync" domain="[('is_sync','=',False)]"/>
</search>
</field>
</record>
# 继承ccs_base模块的form_cc_ship_package_view视图,增加同步日志列表在notebook中
<record model="ir.ui.view" id="form_cc_ship_package_view_inherit">
<field name="name">form_cc_ship_package_view_inherit</field>
<field name="model">cc.ship.package</field>
<field name="inherit_id" ref="ccs_base.form_cc_ship_package_view"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Sync Log">
<field name="sync_log_ids" widget="one2many_list"/>
<field name="bl_sync_log_ids" widget="one2many_list"/>
</page>
</notebook>
</field>
......
<?xml version="1.0" encoding="UTF-8" ?>
<odoo>
<record model="ir.ui.view" id="tree_cc_ship_package_view">
<field name="name">tree.cc.ship.package</field>
<!-- # 继承ccs_base模块的cc_ship_package_view.xml视图,增加is_sync字段在列表中-->
<record model="ir.ui.view" id="tree_cc_ship_package_view_inherit">
<field name="name">tree_cc_ship_package_view_inherit</field>
<field name="model">cc.ship.package</field>
<field name="inherit_id" ref="ccs_base.tree_cc_ship_package_view"/>
<field name="arch" type="xml">
<field name="state" position="after">
<field name="is_sync"/>
</field>
<field name="state" position="replace">
<field name="tk_code" invisible="1"/>
<field optional="show" name="state" string="Progress" widget="badge"
......@@ -13,7 +19,35 @@
decoration-warning="tk_code in ('cb_imcustoms_inspection','cb_imcustoms_exception')"
decoration-muted="tk_code=='cb_import_customs_failure'"/>
</field>
<tree position="attributes">
<attribute name="decoration-danger">is_sync == False</attribute>
</tree>
</field>
</record>
<!-- # 继承ccs_base模块的search_cc_ship_package_view视图,装置加未同步的筛选条件-->
<record model="ir.ui.view" id="search_cc_ship_package_view_inherit">
<field name="name">search_cc_ship_package_view_inherit</field>
<field name="model">cc.ship.package</field>
<field name="inherit_id" ref="ccs_base.search_cc_ship_package_view"/>
<field name="arch" type="xml">
<search position="inside">
<filter string="Not Sync" name="filter_is_sync" domain="[('is_sync','=',False)]"/>
</search>
</field>
</record>
# 继承ccs_base模块的form_cc_ship_package_view视图,增加同步日志列表在notebook中
<record model="ir.ui.view" id="form_cc_ship_package_view_inherit">
<field name="name">form_cc_ship_package_view_inherit</field>
<field name="model">cc.ship.package</field>
<field name="inherit_id" ref="ccs_base.form_cc_ship_package_view"/>
<field name="arch" type="xml">
<notebook position="inside">
<page string="Sync Log">
<field name="sync_log_ids" widget="one2many_list"/>
</page>
</notebook>
</field>
</record>
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论