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

Merge branch 'release/2.8.0'

差异被折叠。
import random
from odoo import models, fields, api from odoo import models, fields, api
...@@ -21,7 +20,7 @@ class CCExceptionInfo(models.Model): ...@@ -21,7 +20,7 @@ class CCExceptionInfo(models.Model):
# 异常编码增加唯一约束 # 异常编码增加唯一约束
_sql_constraints = [('exception_code_uniq', 'unique(exception_code)', 'The Exception Code must be unique.')] _sql_constraints = [('exception_code_uniq', 'unique(exception_code)', 'The Exception Code must be unique.')]
def search_exception_info(self, pda_lang=False): def search_exception_info(self):
""" """
查询包裹异常原因 查询包裹异常原因
:return: :return:
......
...@@ -10,23 +10,70 @@ class CCLastMileProvider(models.Model): ...@@ -10,23 +10,70 @@ class CCLastMileProvider(models.Model):
def _check_matching_value(self): def _check_matching_value(self):
for record in self: for record in self:
if record.matching_value: if record.matching_value:
values = record.matching_value.split('\n') # 将当前记录的值转换为小写
existing_values = '\n'.join(self.search([('id', '!=', record.id)]).mapped('matching_value')).split('\n') values = [value.lower() for value in record.matching_value.split('\n')]
# 获取其他记录的所有匹配值并转换为小写
existing_values = [value.lower() for value in '\n'.join(self.search(
[('id', '!=', record.id)]).mapped('matching_value')).split('\n')]
# 检查是否有重复值(不区分大小写)
if len(values) != len(set(values)) or any(value in existing_values for value in values): if len(values) != len(set(values)) or any(value in existing_values for value in values):
raise ValidationError(_("Matching values must be unique!")) raise ValidationError(_("Matching values must be unique!"))
name = fields.Char(string='Courier Name', required=True) # 快递名称 @api.constrains('placement_area')
def _check_placement_area_unique(self):
for record in self:
if record.placement_area:
placement_area = self.env['common.common'].process_match_str(
record.placement_area)
# 检查所有记录的处理后值是否有重复
pro_map = self.get_all_placement_area(
[('id', '!=', record.id), ('placement_area', '!=', False)])
pro_id = pro_map.get(placement_area)
if pro_id:
raise ValidationError(
_("Placement Area must be unique !"))
logo = fields.Binary('Courier Logo') # 快递logo,英文
name = fields.Char(string='Courier Name', required=True, translate=True) # 快递名称
abbreviation = fields.Char(string='Abbreviation', required=True) # 简称 abbreviation = fields.Char(string='Abbreviation', required=True) # 简称
tape_color_value = fields.Char(string='Tape Color Value') # 胶带色值 tape_color_value = fields.Char(string='Tape Color Value') # 胶带色值
active = fields.Boolean('Active', default=True) # 有效☑️ active = fields.Boolean('Active', default=True) # 有效☑️
matching_value = fields.Text(string='Matching Value') # 尾程服务商匹配值 matching_value = fields.Text(string='Matching Value') # 尾程服务商匹配值
placement_area = fields.Char('Placement Area') # 摆放区域,英文
def match_provider(self, provider_name): def match_provider(self, provider_name):
"""Check if the provider name exists in matching values and return the record.""" """Check if the provider name exists in matching values and return the record."""
# 将输入的 provider_name 转换为小写
provider_name_lower = provider_name.lower()
# 查询所有匹配的记录 # 查询所有匹配的记录
matching_records = self.search([]) matching_records = self.sudo().search([])
# 检查是否有记录的 matching_value 包含 provider_name # 检查是否有记录的 matching_value 包含 provider_name(不区分大小写)
for record in matching_records: for record in matching_records:
if provider_name in record.matching_value.split('\n'): if record.matching_value:
return record # 返回找到的记录 # 将匹配值转换为小写进行比较
matching_values = [value.lower() for value in record.matching_value.split('\n')]
if provider_name_lower in matching_values:
return record # 返回找到的记录
return False # 如果没有找到,返回 None return False # 如果没有找到,返回 None
def get_all_placement_area(self, domain=[]):
"""
获取所有摆放区域
"""
all_providers = self.sudo().search(domain or [])
provider_map = {
self.env['common.common'].process_match_str(provider.placement_area): provider.id
for provider in all_providers
}
return provider_map
def search_pro_info(self):
base_url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
return {
'provider_name': self.name, # 尾程快递名称
"abbreviation": self.abbreviation or '', # 简称
'placement_area': self.placement_area or '', # 摆放区域
'tape_color_value': self.tape_color_value or '', # 胶带色值
'matching_value': self.matching_value or '', # 匹配值
'logo': "%s/web/image/%s/%s/logo" % (base_url, self._name, self.id) if self.logo else '', # 快递logo
}
...@@ -16,6 +16,16 @@ class CommonCommon(models.Model): ...@@ -16,6 +16,16 @@ class CommonCommon(models.Model):
_name = 'common.common' _name = 'common.common'
_description = u'公用基础类' _description = u'公用基础类'
# 去杠去空格转大写
def process_match_str(self, input_str):
"""
处理匹配的字符串,去除杠和空格,并转换为大写
"""
if input_str:
return input_str.replace('-', '').replace('/', '').replace(' ', '').upper()
return input_str
def get_local_time(self, local_time=None, user_obj=False): def get_local_time(self, local_time=None, user_obj=False):
"""获取Odoo时区的时间 """获取Odoo时区的时间
Args: Args:
...@@ -30,8 +40,10 @@ class CommonCommon(models.Model): ...@@ -30,8 +40,10 @@ class CommonCommon(models.Model):
if not user_obj: if not user_obj:
user_obj = self.env.user user_obj = self.env.user
user_tz = user_obj.tz or 'UTC' user_tz = user_obj.tz or 'UTC'
timezone_offset = self.env['common.common'].sudo().get_time_zone(user_tz) timezone_offset = self.env['common.common'].sudo(
local_time = local_time + datetime.timedelta(hours=int(timezone_offset)) ).get_time_zone(user_tz)
local_time = local_time + \
datetime.timedelta(hours=int(timezone_offset))
return local_time.strftime('%Y-%m-%d %H:%M:%S'), timezone_offset return local_time.strftime('%Y-%m-%d %H:%M:%S'), timezone_offset
except Exception as e: except Exception as e:
# 如果出现任何错误,返回UTC时间 # 如果出现任何错误,返回UTC时间
...@@ -51,8 +63,10 @@ class CommonCommon(models.Model): ...@@ -51,8 +63,10 @@ class CommonCommon(models.Model):
if not user_obj: if not user_obj:
user_obj = self.env.user user_obj = self.env.user
user_tz = user_obj.tz or 'UTC' user_tz = user_obj.tz or 'UTC'
timezone_offset = self.env['common.common'].sudo().get_time_zone(user_tz) timezone_offset = self.env['common.common'].sudo(
local_time = local_time + datetime.timedelta(hours=int(timezone_offset)) ).get_time_zone(user_tz)
local_time = local_time + \
datetime.timedelta(hours=int(timezone_offset))
local_tz = pytz.timezone(user_tz) local_tz = pytz.timezone(user_tz)
# 确保时间是本地时区 # 确保时间是本地时区
if local_time.tzinfo is None: if local_time.tzinfo is None:
......
...@@ -12,7 +12,10 @@ class ResConfigSettings(models.TransientModel): ...@@ -12,7 +12,10 @@ class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings' _inherit = 'res.config.settings'
before_min = fields.Integer('清关时间取值(早于清关结束)') before_min = fields.Integer('清关时间取值(早于清关结束)')
package_scan_min = fields.Integer('一键全扫完成时间(min)', help='输入示范:10,即表示在10分钟内大包时间随机分配,并不能重复') package_scan_min = fields.Integer(
'一键全扫完成时间(min)', help='输入示范:10,即表示在10分钟内大包时间随机分配,并不能重复')
is_package_scan = fields.Boolean(
'一键全扫开关', default=False, config_parameter='is_package_scan')
@api.model @api.model
def get_values(self): def get_values(self):
...@@ -24,10 +27,9 @@ class ResConfigSettings(models.TransientModel): ...@@ -24,10 +27,9 @@ class ResConfigSettings(models.TransientModel):
config = self.env['ir.config_parameter'].sudo() config = self.env['ir.config_parameter'].sudo()
before_min = config.get_param('before_min', default=10) before_min = config.get_param('before_min', default=10)
package_scan_min = config.get_param('package_scan_min', default=10) package_scan_min = config.get_param('package_scan_min', default=10)
values.update( values.update(
before_min=before_min, before_min=before_min,
package_scan_min=package_scan_min, package_scan_min=package_scan_min
) )
return values return values
......
...@@ -7,11 +7,13 @@ ...@@ -7,11 +7,13 @@
<sheet> <sheet>
<group> <group>
<group> <group>
<field name="logo" widget="image" class="oe_avatar"/>
<field name="name"/> <!-- 快递名称 --> <field name="name"/> <!-- 快递名称 -->
<field name="abbreviation"/> <!-- 简称 --> <field name="abbreviation"/> <!-- 简称 -->
<field name="tape_color_value" widget="color" required="1"/> <!-- 胶带色值 --> <field name="tape_color_value" widget="color" required="1"/> <!-- 胶带色值 -->
<field name="matching_value" <field name="matching_value"
placeholder="Multiple entries can be made, one matching value per line"/> <!-- 尾程服务商匹配值 --> placeholder="Multiple entries can be made, one matching value per line"/> <!-- 尾程服务商匹配值 -->
<field name="placement_area"/>
</group> </group>
<group> <group>
<field name="active"/> <!-- 有效☑️ --> <field name="active"/> <!-- 有效☑️ -->
...@@ -31,6 +33,7 @@ ...@@ -31,6 +33,7 @@
<field name="abbreviation"/> <!-- 简称 --> <field name="abbreviation"/> <!-- 简称 -->
<field name="tape_color_value"/> <!-- 胶带色值 --> <field name="tape_color_value"/> <!-- 胶带色值 -->
<field name="matching_value"/> <!-- 尾程服务商匹配值 --> <field name="matching_value"/> <!-- 尾程服务商匹配值 -->
<field name="placement_area"/> <!-- 摆放区域 -->
<field name="active"/> <!-- 有效☑️ --> <field name="active"/> <!-- 有效☑️ -->
</tree> </tree>
</field> </field>
...@@ -43,6 +46,7 @@ ...@@ -43,6 +46,7 @@
<search string="Last Mile Provider"> <search string="Last Mile Provider">
<field name="name"/> <field name="name"/>
<field name="abbreviation"/> <field name="abbreviation"/>
<field name="placement_area"/>
</search> </search>
</field> </field>
</record> </record>
......
...@@ -27,6 +27,11 @@ ...@@ -27,6 +27,11 @@
<div class="col-12 col-lg-6 o_setting_box"> <div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_pane"/> <div class="o_setting_left_pane"/>
<div class="o_setting_right_pane"> <div class="o_setting_right_pane">
<div class="text-muted">
<label for="is_package_scan"/>
<field name="is_package_scan"/>
</div>
<div class="text-muted"> <div class="text-muted">
<label for="package_scan_min"/> <label for="package_scan_min"/>
<field name="package_scan_min"/> <field name="package_scan_min"/>
......
from . import tt_controllers from . import tt_controllers
from . import order_controller from . import order_controller
from . import binary
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo.addons.web.controllers.binary import Binary
try:
from werkzeug.utils import send_file
except ImportError:
from odoo.tools._vendor.send_file import send_file
from odoo import http
from odoo.exceptions import UserError
from odoo.http import request
from odoo.tools import replace_exceptions, str2bool
from odoo.tools.image import image_guess_size_from_field_name
_logger = logging.getLogger(__name__)
BAD_X_SENDFILE_ERROR = """\
Odoo is running with --x-sendfile but is receiving /web/filestore requests.
With --x-sendfile enabled, NGINX should be serving the
/web/filestore route, however Odoo is receiving the
request.
This usually indicates that NGINX is badly configured,
please make sure the /web/filestore location block exists
in your configuration file and that it is similar to:
location /web/filestore {{
internal;
alias {data_dir}/filestore;
}}
"""
def clean(name):
return name.replace('\x3c', '')
class AttachmentBinary(Binary):
@http.route(['/web/image',
'/web/image/<string:xmlid>',
'/web/image/<string:xmlid>/<string:filename>',
'/web/image/<string:xmlid>/<int:width>x<int:height>',
'/web/image/<string:xmlid>/<int:width>x<int:height>/<string:filename>',
'/web/image/<string:model>/<int:id>/<string:field>',
'/web/image/<string:model>/<int:id>/<string:field>/<string:filename>',
'/web/image/<string:model>/<int:id>/<string:field>/<int:width>x<int:height>',
'/web/image/<string:model>/<int:id>/<string:field>/<int:width>x<int:height>/<string:filename>',
'/web/image/<int:id>',
'/web/image/<int:id>/<string:filename>',
'/web/image/<int:id>/<int:width>x<int:height>',
'/web/image/<int:id>/<int:width>x<int:height>/<string:filename>',
'/web/image/<int:id>-<string:unique>',
'/web/image/<int:id>-<string:unique>/<string:filename>',
'/web/image/<int:id>-<string:unique>/<int:width>x<int:height>',
'/web/image/<int:id>-<string:unique>/<int:width>x<int:height>/<string:filename>'], type='http',
auth="public", cors="*")
# pylint: disable=redefined-builtin,invalid-name
def content_image(self, xmlid=None, model='ir.attachment', id=None, field='raw',
filename_field='name', filename=None, mimetype=None, unique=False,
download=False, width=0, height=0, crop=False, access_token=None,
nocache=False):
try:
record = request.env['ir.binary'].sudo()._find_record(xmlid, model, id and int(id), access_token)
stream = request.env['ir.binary'].sudo()._get_image_stream_from(
record, field, filename=filename, filename_field=filename_field,
mimetype=mimetype, width=int(width), height=int(height), crop=crop,
)
except UserError as exc:
if download:
raise request.not_found() from exc
# Use the ratio of the requested field_name instead of "raw"
if (int(width), int(height)) == (0, 0):
width, height = image_guess_size_from_field_name(field)
record = request.env.ref('web.image_placeholder').sudo()
stream = request.env['ir.binary']._get_image_stream_from(
record, 'raw', width=int(width), height=int(height), crop=crop,
)
send_file_kwargs = {'as_attachment': download}
if unique:
send_file_kwargs['immutable'] = True
send_file_kwargs['max_age'] = http.STATIC_CACHE_LONG
if nocache:
send_file_kwargs['max_age'] = None
return stream.get_response(**send_file_kwargs)
@http.route(['/web/content',
'/web/content/<string:xmlid>',
'/web/content/<string:xmlid>/<string:filename>',
'/web/content/<int:id>',
'/web/content/<int:id>/<string:filename>',
'/web/content/<string:model>/<int:id>/<string:field>',
'/web/content/<string:model>/<int:id>/<string:field>/<string:filename>'], type='http', auth="public",
cors="*")
# pylint: disable=redefined-builtin,invalid-name
def content_common(self, xmlid=None, model='ir.attachment', id=None, field='raw',
filename=None, filename_field='name', mimetype=None, unique=False,
download=False, access_token=None, nocache=False):
with replace_exceptions(UserError, by=request.not_found()):
record = request.env['ir.binary'].sudo()._find_record(xmlid, model, id and int(id), access_token)
stream = request.env['ir.binary'].sudo()._get_stream_from(record, field, filename, filename_field, mimetype)
if request.httprequest.args.get('access_token'):
stream.public = True
send_file_kwargs = {'as_attachment': str2bool(download)}
if unique:
send_file_kwargs['immutable'] = True
send_file_kwargs['max_age'] = http.STATIC_CACHE_LONG
if nocache:
send_file_kwargs['max_age'] = None
return stream.get_response(**send_file_kwargs)
...@@ -6,6 +6,8 @@ from . import res_config_setting ...@@ -6,6 +6,8 @@ from . import res_config_setting
from . import ao_tt_api_log from . import ao_tt_api_log
from . import cc_node from . import cc_node
from . import cc_bill_loading from . import cc_bill_loading
from . import ir_attachment
from . import http
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import asyncio import asyncio
import json
import logging import logging
import ssl import ssl
from datetime import timedelta, datetime from datetime import timedelta, datetime
import json
import aiohttp import aiohttp
import certifi import certifi
import pytz import pytz
...@@ -280,7 +281,7 @@ class CcBl(models.Model): ...@@ -280,7 +281,7 @@ class CcBl(models.Model):
bl = self.env['cc.bl'].sudo().search( bl = self.env['cc.bl'].sudo().search(
[('bl_no', '=', master_waybill_no), ('create_date', '>=', date)], limit=1) [('bl_no', '=', master_waybill_no), ('create_date', '>=', date)], limit=1)
if bl: if bl:
# 根据kws中获取的"img_detail"中的"img_file_code和img_file_type,生成odoo的附件,并关联到cc.bl的bl_attachment_ids字段 # 根据kws中获取的"img_detail"中的"img_file_code"和img_file_type,生成odoo的附件,并关联到cc.bl的bl_attachment_ids字段
vals = {'customs_bl_no': kws.get('customs_waybill_id'), vals = {'customs_bl_no': kws.get('customs_waybill_id'),
'transport_tool_code': kws.get('transport_code'), 'transport_tool_code': kws.get('transport_code'),
'transport_tool_name': kws.get('transport_name'), 'transport_tool_name': kws.get('transport_name'),
...@@ -367,6 +368,7 @@ class CcBl(models.Model): ...@@ -367,6 +368,7 @@ class CcBl(models.Model):
""" """
根据小包的状态修改提单关务状态以及生成同步日志 根据小包的状态修改提单关务状态以及生成同步日志
:param package_state_obj:小包更新后的状态 :param package_state_obj:小包更新后的状态
:param user_obj:
:return: :return:
""" """
# 根据小包的状态找到对应的提单关务状态 # 根据小包的状态找到对应的提单关务状态
...@@ -540,7 +542,12 @@ class CcBl(models.Model): ...@@ -540,7 +542,12 @@ class CcBl(models.Model):
# 根据小包状态更新提单关务状态 # 根据小包状态更新提单关务状态
try: try:
if is_ok and item.ship_package_ids: if is_ok and item.ship_package_ids:
item.change_customs_state_by_ship_package(item.ship_package_ids[0].state, user_obj=user_obj) # 检查所有小包状态是否一致
states = set(item.ship_package_ids.mapped('state.id'))
if len(states) == 1:
item.change_customs_state_by_ship_package(item.ship_package_ids[0].state, user_obj=user_obj)
else:
logging.info('Not all ship package states are the same, skip updating customs state.')
except Exception as e: except Exception as e:
logging.info('change_customs_state_by_ship_package error:%s' % e) logging.info('change_customs_state_by_ship_package error:%s' % e)
return is_ok return is_ok
...@@ -606,19 +613,22 @@ class CcBl(models.Model): ...@@ -606,19 +613,22 @@ class CcBl(models.Model):
# package_order = self.env['cc.ship.package'].sudo().browse(package_id) # package_order = self.env['cc.ship.package'].sudo().browse(package_id)
if response_data['code'] != 0: if response_data['code'] != 0:
# package_order.is_sync = False # package_order.is_sync = False
update_false_arr.append(package_id) # 更新 is_sync为 False update_false_arr.append(package_id) # 更新 is_sync为 False
error_msg = response_data['msg'] error_msg = response_data['msg']
request_id = response_data['requestID'] request_id = response_data['requestID']
create_api_log_value_arr.append((tracking_no, utc_time, '小包状态轨迹回传:' + error_msg, False, data_text, request_id, '推出', utc_time)) create_api_log_value_arr.append((tracking_no, utc_time, '小包状态轨迹回传:' + error_msg, False,
data_text, request_id, '推出', utc_time))
is_ok = False is_ok = False
else: else:
# 回传成功 # 回传成功
update_true_arr.append(package_id) # 更新 is_sync为 True update_true_arr.append(package_id) # 更新 is_sync为 True
state_arr = package_node_result_dict.get(state, []) state_arr = package_node_result_dict.get(state, [])
tk_code = state_arr[1] if state_arr else '' tk_code = state_arr[1] if state_arr else ''
create_sync_log_value_arr.append((package_id, utc_time, 'Tiktok', tk_code, process_time, state_explain, user_id)) create_sync_log_value_arr.append(
(package_id, utc_time, 'Tiktok', tk_code, process_time, state_explain, user_id))
request_id = response_data['requestID'] request_id = response_data['requestID']
create_api_log_value_arr.append((tracking_no, utc_time, '', True, data_text, request_id, '推出', utc_time)) create_api_log_value_arr.append(
(tracking_no, utc_time, '', True, data_text, request_id, '推出', utc_time))
if update_false_arr: if update_false_arr:
update_false_ids = '(%s)' % str(update_false_arr)[1:-1] update_false_ids = '(%s)' % str(update_false_arr)[1:-1]
sql = "update cc_ship_package set is_sync=False where id in %s" % update_false_ids sql = "update cc_ship_package set is_sync=False where id in %s" % update_false_ids
...@@ -813,13 +823,18 @@ class CcBl(models.Model): ...@@ -813,13 +823,18 @@ class CcBl(models.Model):
if is_ok: if is_ok:
# 根据小包状态更新提单关务状态 # 根据小包状态更新提单关务状态
if self.ship_package_ids: if self.ship_package_ids:
self.change_customs_state_by_ship_package(self.ship_package_ids[0].state, user_obj=user_obj) # 检查所有小包状态是否一致
states = set(self.ship_package_ids.mapped('state.id'))
if len(states) == 1:
self.change_customs_state_by_ship_package(self.ship_package_ids[0].state, user_obj=user_obj)
else:
logging.info('Not all ship package states are the same, skip updating customs state.')
if is_ok: if is_ok:
return is_ok return is_ok
logging.warning(f"Attempt {i + 1}/{max_retries} failed. Retrying...") logging.warning(f"Attempt {i + 1}/{max_retries} failed. Retrying...")
return False return False
def mail_auto_push(self, mail_time=False, ship_packages=[], action_type='tally', mail_db_user='邮件接收', def mail_auto_push(self, mail_time=False, tally_ship_packages=[], action_type='tally', mail_db_user='邮件接收',
pda_db_user='pda'): pda_db_user='pda'):
self = self.with_context(dict(self._context, is_mail=True)) self = self.with_context(dict(self._context, is_mail=True))
for item in self: for item in self:
...@@ -831,14 +846,15 @@ class CcBl(models.Model): ...@@ -831,14 +846,15 @@ class CcBl(models.Model):
item.push_clear_customs_start(before_utc_time) item.push_clear_customs_start(before_utc_time)
user_obj = self.env['res.users'].search([('login', '=', mail_db_user)], limit=1) user_obj = self.env['res.users'].search([('login', '=', mail_db_user)], limit=1)
# 尝试调用 callback_track # 尝试调用 callback_track
if self.try_callback_track(user_obj=user_obj): if item.try_callback_track(user_obj=user_obj):
item.push_clear_customs_end(utc_time) item.push_clear_customs_end(utc_time)
# 再次尝试调用 callback_track # 再次尝试调用 callback_track
if not self.try_callback_track(user_obj=user_obj): if not item.try_callback_track(user_obj=user_obj):
logging.error(f"Failed to push item after {3} attempts.") logging.error(f"Failed to push item after {3} attempts.")
else: else:
logging.error(f"Failed to start process for item after {3} attempts.") logging.error(f"Failed to start process for item after {3} attempts.")
elif ship_packages: elif tally_ship_packages:
ship_packages = [pkg for pkg in tally_ship_packages if pkg.get('bl_id') == item.id]
user_obj = self.env['res.users'].search([('login', '=', pda_db_user)], limit=1) user_obj = self.env['res.users'].search([('login', '=', pda_db_user)], limit=1)
ship_package_ids = [ship_package_dict for sublist in [d['id'] for d in ship_packages] for ship_package_ids = [ship_package_dict for sublist in [d['id'] for d in ship_packages] for
ship_package_dict in sublist] ship_package_dict in sublist]
...@@ -914,7 +930,7 @@ class CcBl(models.Model): ...@@ -914,7 +930,7 @@ class CcBl(models.Model):
self.env.cr.execute(sql) self.env.cr.execute(sql)
self._cr.commit() # 提交事务 self._cr.commit() # 提交事务
self.try_callback_track(max_retries=2, ship_package_ids=ship_package_ids, item.try_callback_track(max_retries=2, ship_package_ids=ship_package_ids,
user_obj=user_obj) user_obj=user_obj)
# 理货或尾程交接的节点 # 理货或尾程交接的节点
# 预先获取所有状态节点 # 预先获取所有状态节点
...@@ -960,9 +976,8 @@ class CcBl(models.Model): ...@@ -960,9 +976,8 @@ class CcBl(models.Model):
self.env.cr.execute(sql) self.env.cr.execute(sql)
self._cr.commit() # 提交事务 self._cr.commit() # 提交事务
self.try_callback_track(max_retries=2, ship_package_ids=ship_package_ids, item.try_callback_track(max_retries=2, ship_package_ids=ship_package_ids,
user_obj=user_obj) user_obj=user_obj)
return True
except Exception as err: except Exception as err:
logging.error('fetch_mail_dlv--error:%s' % str(err)) logging.error('fetch_mail_dlv--error:%s' % str(err))
......
# -*- coding: utf-8 -*-
import logging
from datetime import datetime, timedelta
import time
import hashlib
from odoo import models
from odoo.http import request
__author__ = 'yubo.peng'
_logger = logging.getLogger(__name__)
class AuthenticationError(Exception):
pass
class Http(models.AbstractModel):
_inherit = 'ir.http'
@classmethod
def _auth_method_erp_token(cls):
# 从headers.environ中获取对方传过来的token,timestamp,加密的校验字符串
datas = request.httprequest.headers.environ
if 'HTTP_TOKEN' in datas and 'HTTP_TIMESTAMP' in datas and 'HTTP_CHECKSTR' in datas:
# 从系统参数中获取TOKEt和密钥
factory_secret = request.env['ir.config_parameter'].sudo().get_param('erp_token')
erp_secret_key = request.env['ir.config_parameter'].sudo().get_param('erp_secret_key')
# 从系统参数获取是否时间校验,-1为不校验,其他为校验
check_timeout = int(request.env['ir.config_parameter'].sudo().get_param('check_timeout') or 5)
if not factory_secret:
raise AuthenticationError('系统中未设置ERP TOKEN')
if datas['HTTP_TOKEN'] != factory_secret:
raise AuthenticationError('无效的token')
if check_timeout > 0:
post_time = int(datas['HTTP_TIMESTAMP'])
datetime_post = datetime.fromtimestamp(post_time)
datetime_now = datetime.now().replace(microsecond=0)
datetime_del = datetime_now + timedelta(seconds=check_timeout)
if datetime_post > datetime_del:
raise AuthenticationError('请求已过期')
# 获得sha1_str加密字符串
check_str = '%s%s%s' % (datas['HTTP_TOKEN'], datas['HTTP_TIMESTAMP'], erp_secret_key)
check_crm_str = hashlib.sha1(check_str.encode('utf-8')).hexdigest()
if check_crm_str.upper() != datas['HTTP_CHECKSTR'].upper():
raise AuthenticationError('数据校验不通过')
else:
raise AuthenticationError('请求参数中无token')
# -*- coding: utf-8 -*-
from odoo import models, api, _
from collections import defaultdict
from odoo.exceptions import AccessError
class IrAttachment(models.Model):
_inherit = "ir.attachment"
# override
@api.model
def check(self, mode, values=None):
""" Restricts the access to an ir.attachment, according to referred mode """
if self.env.is_superuser():
return True
# Always require an internal user (aka, employee) to access to a attachment
if not (self.env.is_admin() or self.env.user.has_group('base.group_user')):
raise AccessError(
_("Sorry, you are not allowed to access this document."))
# collect the records to check (by model)
model_ids = defaultdict(set) # {model_name: set(ids)}
if self:
# DLE P173: `test_01_portal_attachment`
self.env['ir.attachment'].flush(['res_model', 'res_id', 'create_uid', 'public', 'res_field'])
self._cr.execute('SELECT res_model, res_id, create_uid, public, res_field FROM ir_attachment WHERE id IN %s', [tuple(self.ids)])
for res_model, res_id, create_uid, public, res_field in self._cr.fetchall():
if public and mode == 'read':
continue
if not (res_model and res_id):
continue
model_ids[res_model].add(res_id)
if values and values.get('res_model') and values.get('res_id'):
model_ids[values['res_model']].add(values['res_id'])
# check access rights on the records
for res_model, res_ids in model_ids.items():
# ignore attachments that are not attached to a resource anymore
# when checking access rights (resource was deleted but attachment
# was not)
if res_model not in self.env:
continue
if res_model == 'res.users' and len(res_ids) == 1 and self.env.uid == list(res_ids)[0]:
# by default a user cannot write on itself, despite the list of writeable fields
# e.g. in the case of a user inserting an image into his image signature
# we need to bypass this check which would needlessly throw us away
continue
records = self.env[res_model].browse(res_ids).exists()
# For related models, check if we can write to the model, as unlinking
# and creating attachments can be seen as an update to the model
access_mode = 'write' if mode in ('create', 'unlink') else mode
records.check_access_rights(access_mode)
records.check_access_rule(access_mode)
@api.model
def read_as_sudo(self, domain=None, fields=None):
return self.sudo().search_read(domain, fields)
...@@ -3,7 +3,7 @@ ...@@ -3,7 +3,7 @@
# 本地 # 本地
db_ip = "127.0.0.1" db_ip = "127.0.0.1"
db_port = "8069" db_port = "8069"
db_name = "hhccs_test" db_name = "hhccs324"
db_user = "admin" db_user = "admin"
db_password = "admin" db_password = "admin"
...@@ -13,13 +13,6 @@ redis_options = dict( ...@@ -13,13 +13,6 @@ redis_options = dict(
db=0 db=0
) )
postgresql_options = dict(
host="127.0.0.1",
port=5431,
database="hh_ccs_test",
user="odoo14",
password="qq166349",
)
# 测试 # 测试
# db_ip = "121.199.167.133" # db_ip = "121.199.167.133"
......
...@@ -37,7 +37,11 @@ class Order_dispose(object): ...@@ -37,7 +37,11 @@ class Order_dispose(object):
bl_obj = self.odoo_db.env['cc.bl'] bl_obj = self.odoo_db.env['cc.bl']
if action_type and not utc_time: if action_type and not utc_time:
bl_obj = self.pda_odoo_db.env['cc.bl'] bl_obj = self.pda_odoo_db.env['cc.bl']
bl_record = bl_obj.browse(data['id']) bl_ids = data.get('ids')
if bl_ids:
bl_record = bl_obj.browse(bl_ids)
else:
bl_record = bl_obj.browse(data['id'])
# utc_time = datetime.strptime(data['utc_time'], "%Y-%m-%d %H:%M:%S") # utc_time = datetime.strptime(data['utc_time'], "%Y-%m-%d %H:%M:%S")
utc_time = data.get('utc_time') utc_time = data.get('utc_time')
user_login = data.get('user_login') user_login = data.get('user_login')
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论