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

Merge branch 'release/2.8.0'

......@@ -6,14 +6,16 @@ msgid ""
msgstr ""
"Project-Id-Version: Odoo Server 16.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2025-04-03 02:14+0000\n"
"PO-Revision-Date: 2025-04-03 02:14+0000\n"
"POT-Creation-Date: 2025-06-09 07:48+0000\n"
"PO-Revision-Date: 2025-06-09 15:53+0800\n"
"Last-Translator: \n"
"Language-Team: \n"
"Language: zh_CN\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: \n"
"Plural-Forms: \n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=1; plural=0;\n"
"X-Generator: Poedit 3.5\n"
#. module: ccs_base
#. odoo-python
......@@ -62,26 +64,32 @@ msgid ""
"<div style=\"margin: 0px; padding: 0px;\">\n"
" <p style=\"margin: 0px; padding: 0px;\">\n"
" Dear all\n"
" <br/>\n"
" <br>\n"
" <!-- 检查 big_package_ids 是否有值 -->\n"
" <t t-if=\"object.big_package_ids\">\n"
" <t t-foreach=\"object.big_package_ids\" t-as=\"big_package_id\">\n"
" <t t-foreach=\"object.big_package_ids\" t-"
"as=\"big_package_id\">\n"
" <div>Package:\n"
" <t t-esc=\"big_package_id.big_package_no or ''\"/>\n"
" <t t-esc=\"big_package_id.big_package_no or "
"''\"></t>\n"
" </div>\n"
" </t>\n"
" </t>\n"
" <!-- 检查 ship_package_ids 是否有值 -->\n"
" <t t-if=\"object.ship_package_ids\">\n"
" <t t-foreach=\"object.ship_package_ids\" t-as=\"ship_package_id\">\n"
" <t t-foreach=\"object.ship_package_ids\" t-"
"as=\"ship_package_id\">\n"
" <div>Package:\n"
" <t t-esc=\"ship_package_id.logistic_order_no or ''\"/>\n"
" <t t-esc=\"ship_package_id."
"logistic_order_no or ''\"></t>\n"
" </div>\n"
" </t>\n"
" </t>\n"
" <div>Please know that there is an exception and the cause of the exception is\n"
" <div>Please know that there is an exception and the "
"cause of the exception is\n"
" <t t-if=\"object.exception_ids\">\n"
" <t t-esc=\"'/'.join([ex.reason for ex in object.exception_ids])\"/>\n"
" <t t-esc=\"'/'.join([ex.reason for ex in object."
"exception_ids])\"></t>\n"
" </t>\n"
" <t t-if=\"not object.exception_ids\">\n"
" No Exception\n"
......@@ -99,26 +107,31 @@ msgid ""
"<div style=\"margin: 0px; padding: 0px;\">\n"
" <p style=\"margin: 0px; padding: 0px;\">\n"
" 您好\n"
" <br/>\n"
" <br>\n"
" <!-- 检查 big_package_ids 是否有值 -->\n"
" <t t-if=\"object.big_package_ids\">\n"
" <t t-foreach=\"object.big_package_ids\" t-as=\"big_package_id\">\n"
" <t t-foreach=\"object.big_package_ids\" t-"
"as=\"big_package_id\">\n"
" <div>包裹:\n"
" <t t-esc=\"big_package_id.big_package_no or ''\"/>\n"
" <t t-esc=\"big_package_id.big_package_no or "
"''\"></t>\n"
" </div>\n"
" </t>\n"
" </t>\n"
" <!-- 检查 ship_package_ids 是否有值 -->\n"
" <t t-if=\"object.ship_package_ids\">\n"
" <t t-foreach=\"object.ship_package_ids\" t-as=\"ship_package_id\">\n"
" <t t-foreach=\"object.ship_package_ids\" t-"
"as=\"ship_package_id\">\n"
" <div>包裹:\n"
" <t t-esc=\"ship_package_id.logistic_order_no or ''\"/>\n"
" <t t-esc=\"ship_package_id."
"logistic_order_no or ''\"></t>\n"
" </div>\n"
" </t>\n"
" </t>\n"
" <div>出现异常,异常原因:\n"
" <t t-if=\"object.exception_ids\">\n"
" <t t-esc=\"'/'.join([ex.reason for ex in object.exception_ids])\"/>,请知晓。\n"
" <t t-esc=\"'/'.join([ex.reason for ex in object."
"exception_ids])\"></t>,请知晓。\n"
" </t>\n"
" <t t-if=\"not object.exception_ids\">\n"
" 无异常,请知晓。\n"
......@@ -380,7 +393,6 @@ msgstr "添加异常信息"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: model_terms:ir.ui.view,arch_db:ccs_base.form_cc_big_package_view
#: model_terms:ir.ui.view,arch_db:ccs_base.form_cc_ship_package_view
#, python-format
......@@ -836,7 +848,6 @@ msgstr "已理货"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/add_exception_info_wizard.py:0
#: code:addons/ccs_base/wizard/add_exception_info_wizard.py:0
#: model:ir.model.fields.selection,name:ccs_base.selection__add_exception_info_wizard__email_language__zh_cn
#, python-format
msgid "Chinese"
......@@ -929,6 +940,11 @@ msgstr "对应大包状态"
msgid "Corresponding to the status of the package"
msgstr "对应小包状态"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_last_mile_provider__logo
msgid "Courier Logo"
msgstr "快递logo"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_last_mile_provider__name
msgid "Courier Name"
......@@ -1244,7 +1260,6 @@ msgstr "目的地港口代码"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/wizard/add_exception_info_wizard.py:0
#: code:addons/ccs_base/wizard/add_exception_info_wizard.py:0
#: model:ir.model.fields.selection,name:ccs_base.selection__add_exception_info_wizard__email_language__en_us
#, python-format
msgid "English"
......@@ -1426,8 +1441,6 @@ msgstr "商品税号"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/models/cc_history_big_package.py:0
#: model:ir.model.fields,field_description:ccs_base.field_cc_big_package__goods_ids
#: model:ir.model.fields,field_description:ccs_base.field_cc_bl__good_ids
......@@ -1950,8 +1963,8 @@ msgid "Link"
msgstr "链接"
#. module: ccs_base
#. odoo-python
#. odoo-javascript
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/static/src/views/list.xml:0
#, python-format
......@@ -2233,7 +2246,7 @@ msgstr ""
#: model:ir.model.fields,help:ccs_base.field_cc_history_ship_package__message_needaction_counter
#: model:ir.model.fields,help:ccs_base.field_cc_ship_package__message_needaction_counter
#: model:ir.model.fields,help:ccs_base.field_order_state_change_rule__message_needaction_counter
msgid "Number of messages which requires an action"
msgid "Number of messages requiring action"
msgstr ""
#. module: ccs_base
......@@ -2389,13 +2402,26 @@ msgstr "托盘号"
msgid "Pallet Usage Date"
msgstr "托盘使用日期"
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_cc_last_mile_provider__placement_area
msgid "Placement Area"
msgstr "摆放区域"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_last_mile_provider.py:0
#, python-format
msgid ""
"Placement Area must be unique !"
msgstr "摆放区域必须唯一!"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#, python-format
msgid ""
"Please configure the default customs clearance status of the bill of loading"
" node type first."
"Please configure the default customs clearance status of the bill of "
"loading node type first."
msgstr "请先配置默认的提单节点类型的清关节点"
#. module: ccs_base
......@@ -2910,7 +2936,6 @@ msgstr "节点序号"
#. module: ccs_base
#. odoo-python
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/models/cc_bill_loading.py:0
#: code:addons/ccs_base/models/cc_history_big_package.py:0
#: model:ir.actions.act_window,name:ccs_base.action_cc_ship_package
#: model:ir.model,name:ccs_base.model_cc_history_ship_package
......@@ -3556,8 +3581,8 @@ msgstr "【清关公司】还没!点击左上角的创建按钮,沙发就是
#. module: ccs_base
#: model_terms:ir.actions.act_window,help:ccs_base.action_cc_clearance_file
msgid ""
"[Clearance File] Not yet! Click the Create button in the top left corner and"
" the sofa is yours!"
"[Clearance File] Not yet! Click the Create button in the top left corner "
"and the sofa is yours!"
msgstr "【清关文件】 还没有!点击左上角的“创建”按钮,沙发就是你的了!"
#. module: ccs_base
......@@ -3608,6 +3633,11 @@ msgstr "【小包】 还没有!点击左上角的“创建”按钮,沙发
msgid "base_info"
msgstr "基本信息"
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.res_config_settings_view_form_auto_push
msgid "pda扫码配置"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_add_exception_info_wizard__action_type
msgid "ship package/big package"
......@@ -3627,7 +3657,18 @@ msgstr ""
#. module: ccs_base
#: model:mail.template,subject:ccs_base.email_template_exception_notification
msgid "{{ ('大包异常' if object.action_type == 'big package' else '小包异常') }}"
msgid ""
"{{ ('大包异常' if object.action_type == 'big package' else '小包异常') }}"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_res_config_settings__package_scan_min
msgid "一键全扫完成时间(min)"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,field_description:ccs_base.field_res_config_settings__is_package_scan
msgid "一键全扫开关"
msgstr ""
#. module: ccs_base
......@@ -3781,6 +3822,11 @@ msgstr ""
msgid "请求id"
msgstr ""
#. module: ccs_base
#: model:ir.model.fields,help:ccs_base.field_res_config_settings__package_scan_min
msgid "输入示范:10,即表示在10分钟内大包时间随机分配,并不能重复"
msgstr ""
#. module: ccs_base
#: model_terms:ir.ui.view,arch_db:ccs_base.search_history_tt_api_log_view
msgid "近30日日志"
......
import random
from odoo import models, fields, api
......@@ -21,7 +20,7 @@ class CCExceptionInfo(models.Model):
# 异常编码增加唯一约束
_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:
......
......@@ -10,23 +10,70 @@ class CCLastMileProvider(models.Model):
def _check_matching_value(self):
for record in self:
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):
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) # 简称
tape_color_value = fields.Char(string='Tape Color Value') # 胶带色值
active = fields.Boolean('Active', default=True) # 有效☑️
matching_value = fields.Text(string='Matching Value') # 尾程服务商匹配值
placement_area = fields.Char('Placement Area') # 摆放区域,英文
def match_provider(self, provider_name):
"""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_value 包含 provider_name
matching_records = self.sudo().search([])
# 检查是否有记录的 matching_value 包含 provider_name(不区分大小写)
for record in matching_records:
if provider_name in record.matching_value.split('\n'):
if record.matching_value:
# 将匹配值转换为小写进行比较
matching_values = [value.lower() for value in record.matching_value.split('\n')]
if provider_name_lower in matching_values:
return record # 返回找到的记录
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):
_name = 'common.common'
_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):
"""获取Odoo时区的时间
Args:
......@@ -30,8 +40,10 @@ class CommonCommon(models.Model):
if not user_obj:
user_obj = self.env.user
user_tz = user_obj.tz or 'UTC'
timezone_offset = self.env['common.common'].sudo().get_time_zone(user_tz)
local_time = local_time + datetime.timedelta(hours=int(timezone_offset))
timezone_offset = self.env['common.common'].sudo(
).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
except Exception as e:
# 如果出现任何错误,返回UTC时间
......@@ -51,8 +63,10 @@ class CommonCommon(models.Model):
if not user_obj:
user_obj = self.env.user
user_tz = user_obj.tz or 'UTC'
timezone_offset = self.env['common.common'].sudo().get_time_zone(user_tz)
local_time = local_time + datetime.timedelta(hours=int(timezone_offset))
timezone_offset = self.env['common.common'].sudo(
).get_time_zone(user_tz)
local_time = local_time + \
datetime.timedelta(hours=int(timezone_offset))
local_tz = pytz.timezone(user_tz)
# 确保时间是本地时区
if local_time.tzinfo is None:
......
......@@ -12,7 +12,10 @@ class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'
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
def get_values(self):
......@@ -24,10 +27,9 @@ class ResConfigSettings(models.TransientModel):
config = self.env['ir.config_parameter'].sudo()
before_min = config.get_param('before_min', default=10)
package_scan_min = config.get_param('package_scan_min', default=10)
values.update(
before_min=before_min,
package_scan_min=package_scan_min,
package_scan_min=package_scan_min
)
return values
......
......@@ -7,11 +7,13 @@
<sheet>
<group>
<group>
<field name="logo" widget="image" class="oe_avatar"/>
<field name="name"/> <!-- 快递名称 -->
<field name="abbreviation"/> <!-- 简称 -->
<field name="tape_color_value" widget="color" required="1"/> <!-- 胶带色值 -->
<field name="matching_value"
placeholder="Multiple entries can be made, one matching value per line"/> <!-- 尾程服务商匹配值 -->
<field name="placement_area"/>
</group>
<group>
<field name="active"/> <!-- 有效☑️ -->
......@@ -31,6 +33,7 @@
<field name="abbreviation"/> <!-- 简称 -->
<field name="tape_color_value"/> <!-- 胶带色值 -->
<field name="matching_value"/> <!-- 尾程服务商匹配值 -->
<field name="placement_area"/> <!-- 摆放区域 -->
<field name="active"/> <!-- 有效☑️ -->
</tree>
</field>
......@@ -43,6 +46,7 @@
<search string="Last Mile Provider">
<field name="name"/>
<field name="abbreviation"/>
<field name="placement_area"/>
</search>
</field>
</record>
......
......@@ -27,6 +27,11 @@
<div class="col-12 col-lg-6 o_setting_box">
<div class="o_setting_left_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">
<label for="package_scan_min"/>
<field name="package_scan_min"/>
......
from . import tt_controllers
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)
......@@ -49,7 +49,8 @@ class OrderController(http.Controller):
# system_user = system_user.with_context(lang=lang)
try:
if kwargs.get('login') and kwargs.get('password'):
uid = request.session.authenticate(request.session.db, kwargs['login'], kwargs['password'])
uid = request.session.authenticate(
request.session.db, kwargs['login'], kwargs['password'])
user = request.env['res.users'].sudo().browse(uid)
res['user_info'] = {
'id': uid, # 用户id
......@@ -58,21 +59,37 @@ class OrderController(http.Controller):
res['state'] = 200
else:
res['state'] = 202
res['message'] = error_msg_dic[pda_lang] # _('Login name and password cannot be empty') # 登录名、密码不能为空
# _('Login name and password cannot be empty') # 登录名、密码不能为空
res['message'] = error_msg_dic[pda_lang]
except exceptions.AccessDenied as e:
if e.args == exceptions.AccessDenied().args:
res['message'] = exceptions_msg_dic[pda_lang] # _("Wrong login/password") # 错误的登录名或密码
# _("Wrong login/password") # 错误的登录名或密码
res['message'] = exceptions_msg_dic[pda_lang]
else:
res['message'] = e.args[0]
logging.info('api_cc_login error:%s' % res)
return res
@http.route('/api/one_key_full_scan/info', type='json', auth='public', csrf=False)
def one_key_full_scan_info(self):
"""
查询一键全扫信息接口,返回是否一键全扫和完成时间
入参:bl_no
"""
# kwargs = json.loads(request.httprequest.data)
res = {'state': 201, 'message': ''}
res['package_scan_min'] = int(
request.env['res.config.settings'].sudo().get_values().get('package_scan_min'))
res['is_package_scan'] = bool(request.env['ir.config_parameter'].sudo(
).get_param('is_package_scan'))
res['state'] = 200
return res
@http.route('/api/bl/info', type='json', auth='public', methods=['GET', 'POST'], csrf=False)
def bl_info(self):
"""
查看提单以及大包,小包和托盘信息
:param kwargs:
:return:
"""
kwargs = json.loads(request.httprequest.data)
......@@ -85,17 +102,22 @@ class OrderController(http.Controller):
bl_no = kwargs['bl_no']
# bl_obj = request.env['cc.bl'].sudo().search([('bl_no', '=', bl_no)]) # 提单
state_arr = ['draft', 'ccing']
bl_obj = request.env['cc.bl'].sudo().deal_bl_no(bl_no) # 提单号去掉杠和空格,并转换为小写
bl_obj = request.env['cc.bl'].sudo().deal_bl_no(
bl_no) # 提单号去掉杠和空格,并转换为小写
if bl_obj:
if bl_obj.state in state_arr:
res['bl_info'] = bl_obj.search_bl_info(pda_lang=pda_lang, type=action_type)
res['package_scan_min'] = int(request.env['res.config.settings'].sudo().get_values().get('package_scan_min'))
res['bl_info'] = bl_obj.search_bl_info(
pda_lang=pda_lang, type=action_type)
res['package_scan_min'] = int(
request.env['res.config.settings'].sudo().get_values().get('package_scan_min'))
res['state'] = 200
else:
res['message'] = bill_state_msg_dic[pda_lang] # 没有在系统中找到未完成清关的该提单信息
# 没有在系统中找到未完成清关的该提单信息
res['message'] = bill_state_msg_dic[pda_lang]
else:
res['state'] = 404
res['message'] = bill_noexist_msg_dic[pda_lang] # _('Bill of lading does not exist') # 提单不存在
# _('Bill of lading does not exist') # 提单不存在
res['message'] = bill_noexist_msg_dic[pda_lang]
else:
res['state'] = 202
res['message'] = bill_null_msg_dic[
......@@ -115,7 +137,6 @@ class OrderController(http.Controller):
def update_big_package_tally_detail(self):
"""
修改理货信息
:param kwargs:
:return:
"""
kwargs = json.loads(request.httprequest.data)
......@@ -128,7 +149,8 @@ class OrderController(http.Controller):
kwargs.get('big_package_arr') or kwargs.get('ship_package_arr') or kwargs.get('pallet_arr')):
bl_no = kwargs['bl_no']
state_arr = ['draft', 'ccing']
bl_obj = request.env['cc.bl'].sudo().deal_bl_no(bl_no) # 提单号去掉杠和空格,并转换为小写
bl_obj = request.env['cc.bl'].sudo().deal_bl_no(
bl_no) # 提单号去掉杠和空格,并转换为小写
if bl_obj and bl_obj.state in state_arr:
ship_packages = []
big_package_exception_arr = {}
......@@ -141,7 +163,8 @@ class OrderController(http.Controller):
file_str = 'big_package_no' if package_type == 'big' else (
'logistic_order_no' if package_type == 'ship' else 'pallet_number') # 大包号/物流订单号
package_no = package_item.get(file_str) # 包裹号
exception_cause_ids = package_item.get('exception_cause_ids') # 异常原因id数组
exception_cause_ids = package_item.get(
'exception_cause_ids') # 异常原因id数组
if package_type == 'pallet':
package_obj = request.env['cc.big.package'].sudo().search(
[('pallet_number', '=', package_no), ('bl_id', '=', bl_obj.id)]) # 多个
......@@ -153,13 +176,16 @@ class OrderController(http.Controller):
for excep_item in exception_cause_ids:
if package_type == 'ship':
if excep_item not in ship_package_exception_arr:
ship_package_exception_arr[excep_item] = []
ship_package_exception_arr[excep_item] = [
]
ship_package_exception_arr[excep_item] += package_obj.ids
else:
if excep_item not in big_package_exception_arr:
big_package_exception_arr[excep_item] = []
big_package_exception_arr[excep_item] = [
]
big_package_exception_arr[excep_item] += package_obj.ids
package_obj.update_exception_info(exception_cause_ids) # 修改异常信息
package_obj.update_exception_info(
exception_cause_ids) # 修改异常信息
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(
......@@ -179,7 +205,8 @@ class OrderController(http.Controller):
'tally_time': tally_time
}) # 小包
package_obj.update_big_package_info(action_type=action_type,
tally_state=package_item.get('tally_state'),
tally_state=package_item.get(
'tally_state'),
tally_user_id=package_item.get(
'tally_user_id'),
tally_time=tally_time) # 修改理货信息
......@@ -189,7 +216,8 @@ class OrderController(http.Controller):
# 处理小包、大包和托盘
if kwargs.get('ship_package_arr'):
error_no_arr = process_packages(kwargs['ship_package_arr'], 'ship', ship_packages)
error_no_arr = process_packages(
kwargs['ship_package_arr'], 'ship', ship_packages)
if error_no_arr:
res['message'] = {
'en': 'Ship package number [%s] does not exist' % ','.join(error_no_arr),
......@@ -198,7 +226,8 @@ class OrderController(http.Controller):
return res
if kwargs.get('big_package_arr'):
error_no_arr = process_packages(kwargs['big_package_arr'], 'big', ship_packages)
error_no_arr = process_packages(
kwargs['big_package_arr'], 'big', ship_packages)
if error_no_arr:
res['message'] = {
'en': 'Big package number [%s] does not exist' % ','.join(error_no_arr),
......@@ -207,7 +236,8 @@ class OrderController(http.Controller):
return res
if kwargs.get('pallet_arr'):
error_no_arr = process_packages(kwargs['pallet_arr'], 'pallet', ship_packages)
error_no_arr = process_packages(
kwargs['pallet_arr'], 'pallet', ship_packages)
if error_no_arr:
res['message'] = {
'en': 'Tray number [%s] does not have a corresponding big package' % ','.join(
......@@ -238,10 +268,12 @@ class OrderController(http.Controller):
email_language=lang)
ship_wizard_obj.confirm() # 发送邮件
res['state'] = 200
logging.info('update_big_package_tally_detail ship_packages:%s' % len(ship_packages))
logging.info(
'update_big_package_tally_detail ship_packages:%s' % len(ship_packages))
# 有小包 就更新小包状态和同步
if ship_packages:
redis_conn = request.env['common.common'].sudo().get_redis()
redis_conn = request.env['common.common'].sudo(
).get_redis()
if redis_conn and redis_conn != 'no':
# redis_conn.lpush('push_ship_package_state', json.dumps(
# {'bl_id': bl_obj.id, 'ship_package_ids': ship_package_ids}))
......@@ -266,6 +298,152 @@ class OrderController(http.Controller):
logging.info('res:%s' % res)
return res
@http.route('/api/update/pro/big/package/tally/detail', type='json', auth='public', methods=['GET', 'POST'],
csrf=False)
def update_pro_big_package_tally_detail(self):
"""
修改尾程快递的理货信息
:return:
"""
kwargs = json.loads(request.httprequest.data)
pda_lang = kwargs.get('pda_lang') or 'zh'
res = {'state': 201, 'message': ''}
action_type = kwargs.get('action_type') or 'tally' # tally / handover
try:
logging.info('update_pro_big_package_tally_detail kw:%s' % kwargs)
if action_type and (kwargs.get('big_package_arr') or kwargs.get('ship_package_arr')):
ship_packages = []
big_package_exception_arr = {}
ship_package_exception_arr = {}
# 处理包裹信息
def process_packages(package_arr, package_type, ship_packages):
error_no_set = set() # 使用集合来存储错误信息
for package_item in package_arr:
file_str = 'big_package_no' if package_type == 'big' else (
'logistic_order_no' if package_type == 'ship' else 'pallet_number') # 大包号/物流订单号
package_no = package_item.get(file_str) # 包裹号
exception_cause_ids = package_item.get(
'exception_cause_ids') # 异常原因id数组
package_obj = request.env[f'cc.{package_type}.package'].sudo().search(
[(file_str, '=', package_no)]) # 小包/大包 1个
if package_obj:
if exception_cause_ids:
for excep_item in exception_cause_ids:
if package_type == 'ship':
if excep_item not in ship_package_exception_arr:
ship_package_exception_arr[excep_item] = [
]
ship_package_exception_arr[excep_item] += package_obj.ids
else:
if excep_item not in big_package_exception_arr:
big_package_exception_arr[excep_item] = [
]
big_package_exception_arr[excep_item] += package_obj.ids
package_obj.update_exception_info(
exception_cause_ids) # 修改异常信息
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'):
if package_type == 'ship':
ship_packages.append({
'id': [package_obj.id],
'bl_id': package_obj.bl_id.id,
'tally_time': tally_time})
else:
for package in package_obj:
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,
'bl_id': package.bl_id.id,
'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(
'tally_user_id'),
tally_time=tally_time) # 修改理货信息
else:
error_no_set.add(package_no)
return error_no_set
# 处理小包、大包
if kwargs.get('ship_package_arr'):
error_no_arr = process_packages(
kwargs['ship_package_arr'], 'ship', ship_packages)
if error_no_arr:
res['message'] = {
'en': 'Ship package number [%s] does not exist' % ','.join(error_no_arr),
'zh': '小包物流订单号[%s]不存在' % ','.join(error_no_arr)
}[pda_lang]
return res
if kwargs.get('big_package_arr'):
error_no_arr = process_packages(
kwargs['big_package_arr'], 'big', ship_packages)
if error_no_arr:
res['message'] = {
'en': 'Big package number [%s] does not exist' % ','.join(error_no_arr),
'zh': '大包号[%s]不存在' % ','.join(error_no_arr)
}[pda_lang]
return res
# 修改异常原因,发送异常邮件
lang = 'zh_CN' if pda_lang == 'zh' else 'en_US' # 语言
for exception_id, big_package in big_package_exception_arr.items():
if big_package:
big_wizard_obj = request.env[
'add.exception.info.wizard'].sudo().with_context({'active_id': big_package,
'active_name': 'cc.big.package',
'not_update_ex': True}).create_add_exception_wizard(
'big package', [exception_id], big_package_ids=big_package, send_email=True,
email_language=lang)
big_wizard_obj.confirm() # 发送邮件
for exception_id, ship_package in ship_package_exception_arr.items():
if ship_package:
ship_wizard_obj = request.env[
'add.exception.info.wizard'].sudo().with_context({'active_id': ship_package,
'active_name': 'cc.ship.package',
'not_update_ex': True}).create_add_exception_wizard(
'ship package', [exception_id], ship_package_ids=ship_package, send_email=True,
email_language=lang)
ship_wizard_obj.confirm() # 发送邮件
res['state'] = 200
logging.info(
'update_big_package_tally_detail ship_packages:%s' % len(ship_packages))
# 有小包 就更新小包状态和同步
if ship_packages:
redis_conn = request.env['common.common'].sudo().get_redis()
if redis_conn and redis_conn != 'no':
# redis_conn.lpush('push_ship_package_state', json.dumps(
# {'bl_id': bl_obj.id, 'ship_package_ids': ship_package_ids}))
bl_ids = [ship_package.get('bl_id') for ship_package in ship_packages]
logging.info('bl_ids:%s' % bl_ids)
redis_conn.lpush('mail_push_package_list', json.dumps(
{'ids': list(set(bl_ids)), 'ship_packages': str(ship_packages), 'action_type': action_type}))
else:
null_msg_dic = {
'en': 'The bill of lading number and action type must be provided; at least one of the following is required: big package data or ship package data.',
'zh': '类型必须提供;大包数据或小包数据至少需要提供一个。'
}
res['message'] = null_msg_dic[pda_lang]
except Exception as e:
logging.info('update_pro_big_package_tally_detail error:%s' % e)
exceptions_msg_dic = {
'en': 'System parsing error, the reason for the error is %s' % e,
'zh': '系统解析错误,错误原因是%s' % e
}
res['message'] = exceptions_msg_dic[pda_lang]
logging.info('res:%s' % res)
return res
@http.route('/api/exceptions/info', type='json', auth='public', methods=['GET', 'POST'], csrf=False)
def exceptions_info(self):
"""
......@@ -278,7 +456,7 @@ class OrderController(http.Controller):
logging.info('exceptions_info kwargs:%s' % kwargs)
lang = 'zh_CN' if pda_lang == 'zh' else 'en_US' # 语言
exception_obj = request.env['cc.exception.info'].sudo().with_context({'lang': lang}).search([]) # 包裹异常原因
res['exception_arr'] = [excep.search_exception_info(pda_lang=pda_lang) for excep in exception_obj]
res['exception_arr'] = [excep.search_exception_info() for excep in exception_obj]
res['state'] = 200
except Exception as e:
exceptions_msg_dic = {
......@@ -290,3 +468,84 @@ class OrderController(http.Controller):
pda_lang] # _('System parsing error, the reason for the error is %s', e) # 系统解析错误,错误原因是
logging.info('exceptions_info res:%s' % res)
return res
@http.route('/api/last_mile/tally', type='json', auth='public', csrf=False)
def last_mile_tally(self):
"""
按尾程快递理货的接口,查询所有清关中的提单关联的大包,且大包状态为未理货的数量,按下一阶段服务商名称分组,下一个阶段服务商名称匹配尾程快递;传给PDA。
尾程快递名称,摆放区域,快递LOGO,大包件数
大包信息字段:大包号,尾程快递名称,尾程快递色值;
"""
kwargs = json.loads(request.httprequest.data)
pda_lang = kwargs.get('pda_lang') or 'zh'
res = {'state': 201, 'message': ''}
try:
logging.info('last_mile_tally kwargs:%s' % kwargs)
return self._get_last_mile_grouped('unprocessed_goods', pda_lang)
except Exception as e:
exceptions_msg_dic = {
'en': 'System parsing error, the reason for the error is %s' % e,
'zh': '系统解析错误,错误原因是%s' % e
}
logging.info('last_mile_tally error:%s' % e)
res['message'] = exceptions_msg_dic[
pda_lang] # _('System parsing error, the reason for the error is %s', e) # 系统解析错误,错误原因是
logging.info('last_mile_tally res:%s' % res)
return res
@http.route('/api/last_mile/delivery', type='json', auth='public', csrf=False)
def last_mile_delivery(self):
"""
按尾程快递交货接口,查询系统所有清关中的提单关联的大包,且大包状态为已理货的数量,按下一阶段服务商名称分组,下一个阶段服务商名称匹配尾程快递传给PDA。传输字段与理货的一致。
"""
kwargs = json.loads(request.httprequest.data)
pda_lang = kwargs.get('pda_lang') or 'zh'
res = {'state': 201, 'message': ''}
try:
logging.info('last_mile_delivery kwargs:%s' % kwargs)
return self._get_last_mile_grouped('checked_goods', pda_lang)
except Exception as e:
exceptions_msg_dic = {
'en': 'System parsing error, the reason for the error is %s' % e,
'zh': '系统解析错误,错误原因是%s' % e
}
logging.info('last_mile_delivery error:%s' % e)
res['message'] = exceptions_msg_dic[
pda_lang] # _('System parsing error, the reason for the error is %s', e) # 系统解析错误,错误原因是
logging.info('last_mile_delivery res:%s' % res)
return res
def _get_last_mile_grouped(self, tally_state, pda_lang):
lang = 'zh_CN' if pda_lang == 'zh' else 'en_US' # 语言
# 1. 查所有清关中提单
bls = request.env['cc.bl'].sudo().search([('state', '=', 'ccing')])
# 2. 查所有大包
big_packages = request.env['cc.big.package'].sudo().search([
('bl_id', 'in', bls.ids),
('tally_state', '=', tally_state)
])
# 3. 按"下一阶段服务商名称"分组
group_dict = {}
for pkg in big_packages:
provider = request.env['cc.last.mile.provider'].sudo().with_context({'lang': lang}).match_provider(
pkg.next_provider_name)
if not provider:
continue
key = provider.id
if key not in group_dict:
group_dict[key] = provider.search_pro_info() # 查询快递信息
group_dict[key]['count'] = 0
group_dict[key]['big_package_arr'] = []
group_dict[key]['ship_package_arr'] = []
group_dict[key]['count'] += 1
group_dict[key]['big_package_arr'].append(pkg.search_big_package_info(pda_lang=pda_lang, type=tally_state))
group_dict[key]['ship_package_arr'].extend(
[ship_package_item.search_ship_package_info(pda_lang=pda_lang) for ship_package_item in
pkg.ship_package_ids])
# 4. 返回
provider_info_arr = list(group_dict.values())
# 按服务商名称升序排序
provider_info_arr.sort(key=lambda x: x.get('name', ''))
return {'provider_info_arr': provider_info_arr, 'state': 200}
......@@ -6,6 +6,8 @@ from . import res_config_setting
from . import ao_tt_api_log
from . import cc_node
from . import cc_bill_loading
from . import ir_attachment
from . import http
# -*- coding: utf-8 -*-
import asyncio
import json
import logging
import ssl
from datetime import timedelta, datetime
import json
import aiohttp
import certifi
import pytz
......@@ -280,7 +281,7 @@ class CcBl(models.Model):
bl = self.env['cc.bl'].sudo().search(
[('bl_no', '=', master_waybill_no), ('create_date', '>=', date)], limit=1)
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'),
'transport_tool_code': kws.get('transport_code'),
'transport_tool_name': kws.get('transport_name'),
......@@ -367,6 +368,7 @@ class CcBl(models.Model):
"""
根据小包的状态修改提单关务状态以及生成同步日志
:param package_state_obj:小包更新后的状态
:param user_obj:
:return:
"""
# 根据小包的状态找到对应的提单关务状态
......@@ -540,7 +542,12 @@ class CcBl(models.Model):
# 根据小包状态更新提单关务状态
try:
if is_ok and item.ship_package_ids:
# 检查所有小包状态是否一致
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:
logging.info('change_customs_state_by_ship_package error:%s' % e)
return is_ok
......@@ -609,16 +616,19 @@ class CcBl(models.Model):
update_false_arr.append(package_id) # 更新 is_sync为 False
error_msg = response_data['msg']
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
else:
# 回传成功
update_true_arr.append(package_id) # 更新 is_sync为 True
state_arr = package_node_result_dict.get(state, [])
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']
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:
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
......@@ -813,13 +823,18 @@ class CcBl(models.Model):
if is_ok:
# 根据小包状态更新提单关务状态
if self.ship_package_ids:
# 检查所有小包状态是否一致
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:
return is_ok
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', mail_db_user='邮件接收',
def mail_auto_push(self, mail_time=False, tally_ship_packages=[], action_type='tally', mail_db_user='邮件接收',
pda_db_user='pda'):
self = self.with_context(dict(self._context, is_mail=True))
for item in self:
......@@ -831,14 +846,15 @@ class CcBl(models.Model):
item.push_clear_customs_start(before_utc_time)
user_obj = self.env['res.users'].search([('login', '=', mail_db_user)], limit=1)
# 尝试调用 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)
# 再次尝试调用 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.")
else:
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)
ship_package_ids = [ship_package_dict for sublist in [d['id'] for d in ship_packages] for
ship_package_dict in sublist]
......@@ -914,7 +930,7 @@ class CcBl(models.Model):
self.env.cr.execute(sql)
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)
# 理货或尾程交接的节点
# 预先获取所有状态节点
......@@ -960,9 +976,8 @@ class CcBl(models.Model):
self.env.cr.execute(sql)
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)
return True
except Exception as 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 @@
# 本地
db_ip = "127.0.0.1"
db_port = "8069"
db_name = "hhccs_test"
db_name = "hhccs324"
db_user = "admin"
db_password = "admin"
......@@ -13,13 +13,6 @@ redis_options = dict(
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"
......
......@@ -37,6 +37,10 @@ class Order_dispose(object):
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_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 = data.get('utc_time')
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论