diff --git a/app_common/__manifest__.py b/app_common/__manifest__.py index 67eb35ce..13bb47a9 100644 --- a/app_common/__manifest__.py +++ b/app_common/__manifest__.py @@ -1,16 +1,22 @@ # -*- coding: utf-8 -*- -# Created on 20120-01-05 +# Created on 2023-02-02 # author: 欧度智能,https://www.odooai.cn # email: 300883@qq.com # resource of odooai # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -# Odoo12在线用户手册(长期更新) -# https://www.odooai.cn/documentation/user/12.0/zh_CN/index.html +# Odoo16在线用户手册(长期更新) +# https://www.odooai.cn/documentation/16.0/zh_CN/index.html -# Odoo12在线开发者手册(长期更新) -# https://www.odooai.cn/documentation/12.0/index.html +# Odoo16在线开发者手册(长期更新) +# https://www.odooai.cn/documentation/16.0/zh_CN/developer.html + +# Odoo13在线用户手册(长期更新) +# https://www.odooai.cn/documentation/user/13.0/zh_CN/index.html + +# Odoo13在线开发者手册(长期更新) +# https://www.odooai.cn/documentation/13.0/index.html # Odoo10在线中文用户手册(长期更新) # https://www.odooai.cn/documentation/user/10.0/zh_CN/index.html @@ -33,10 +39,11 @@ { 'name': "odooai Odooapp Common Func", - 'version': '15.21.11.30', + 'version': '15.23.09.28', 'author': 'odooai.cn', 'category': 'Base', 'website': 'https://www.odooai.cn', + 'live_test_url': 'https://demo.odooapp.cn', 'license': 'LGPL-3', 'sequence': 2, 'price': 0.00, @@ -47,27 +54,26 @@ 基础核心,必须没有要被依赖字段及视图等,实现auto_install ''', 'description': ''' - Support Odoo 15, Enterprise and Community Edition + Support Odoo 16, 15, Enterprise and Community Edition + need to setup odoo.conf, add follow: + server_wide_modules = web,app_common 1. 2. 3. Multi-language Support. 4. Multi-Company Support. - 5. Support Odoo 15, Enterprise and Community Edition + 5. Support Odoo 16, 15, Enterprise and Community Edition ========== 1. 2. 3. 多语言支持 4. 多公司支持 - 5. Odoo 15, 企业版,社区版,多版本支持 + 5. Odoo 16, 15, 企业版,社区版,多版本支持 ''', 'depends': [ - 'base', + 'mail', 'web', ], 'data': [ - # 'security/*.xml', - # 'security/ir.model.access.csv', - # 'data/.xml', 'views/ir_cron_views.xml', # 'report/.xml', ], diff --git a/app_common/controllers/main.py b/app_common/controllers/main.py index fe720a53..2e7e21f4 100644 --- a/app_common/controllers/main.py +++ b/app_common/controllers/main.py @@ -6,6 +6,8 @@ import requests from math import radians, cos, sin, asin, sqrt from ..lib.user_agents import parse +from ..models.base import get_ua_type + from odoo import api, http, SUPERUSER_ID, _ from odoo import http, exceptions @@ -26,54 +28,17 @@ class AppController(http.Controller): # 返回这个图片的base64编码 return base64.b64encode(BytesIO(response.content).read()) - @http.route('/web/ua/show', auth='public', methods=['GET']) + @http.route(['/my/ua', '/wxa/ua', '/web/ua', '/web/ua/show'], auth='public', methods=['GET']) def app_ua_show(self): # https://github.com/selwin/python-user-agents ua_string = request.httprequest.headers.get('User-Agent') user_agent = parse(ua_string) - ua_type = self.get_ua_type() + ua_type = get_ua_type() ustr = "Request UA:
%s
Parse UA:
%s
UA Type:
%s
" % (ua_string, str(user_agent), ua_type) return request.make_response(ustr, [('Content-Type', 'text/html')]) def get_ua_type(self): - ua = request.httprequest.headers.get('User-Agent') - # 临时用 agent 处理,后续要前端中正确处理或者都从后台来 - # 微信浏览器 - # MicroMessenger: Mozilla/5.0 (Linux; Android 10; ELE-AL00 Build/HUAWEIELE-AL00; wv) - # AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 - # MQQBrowser/6.2 TBS/045525 Mobile Safari/537.36 MMWEBID/3135 MicroMessenger/8.0.2.1860(0x2800023B) Process/tools WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 - # 微信浏览器,开发工具,网页 iphone - # ,Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 - # wechatdevtools/1.03.2011120 MicroMessenger/7.0.4 Language/zh_CN webview/16178807094901773 - # webdebugger port/27772 token/b91f4a234b918f4e2a5d1a835a09c31e - - # 微信小程序 - # MicroMessenger: Mozilla/5.0 (Linux; Android 10; ELE-AL00 Build/HUAWEIELE-AL00; wv) - # AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.62 XWEB/2767 MMWEBSDK/20210302 Mobile Safari/537.36 MMWEBID/6689 MicroMessenger/8.0.2.1860(0x2800023B) Process/appbrand2 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 - # MiniProgramEnv/android - # 微信浏览器,开发工具,小程序,iphone - # Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 - # wechatdevtools/1.03.2011120 MicroMessenger/7.0.4 Language/zh_CN webview/ - # 微信内,iphone web - # Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 - # MicroMessenger/8.0.3(0x1800032a) NetType/WIFI Language/zh_CN - # 安卓app,h5 - # ELE-AL00(Android/10) (cn.erpapp.o20sticks.App/13.20.12.09) Weex/0.26.0 1080x2265 - - utype = 'web' - # todo: 引入现成 py lib,处理企业微信 - if 'MicroMessenger' in ua and 'webdebugger' not in ua and ('MiniProgramEnv' in ua or 'wechatdevtools' in ua): - # 微信小程序及开发者工具 - utype = 'wxapp' - elif 'MicroMessenger' in ua: - # 微信浏览器 - utype = 'wxweb' - elif 'cn.erpapp.o20sticks.App' in ua: - # 安卓app - utype = 'native_android' - # _logger.warning('=========get ua %s,%s' % (utype, ua)) - return utype - + return get_ua_type() def haversine(lon1, lat1, lon2, lat2): # 计算地图上两点的距离 diff --git a/app_common/hooks.py b/app_common/hooks.py index e6d66da3..40a5ccf5 100644 --- a/app_common/hooks.py +++ b/app_common/hooks.py @@ -6,18 +6,6 @@ # resource of odooai # License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl). -# Odoo16在线用户手册(长期更新) -# https://www.odooai.cn/documentation/16.0/zh_CN/index.html - -# Odoo16在线开发者手册(长期更新) -# https://www.odooai.cn/documentation/16.0/zh_CN/developer.html - -# Odoo13在线用户手册(长期更新) -# https://www.odooai.cn/documentation/user/13.0/zh_CN/index.html - -# Odoo13在线开发者手册(长期更新) -# https://www.odooai.cn/documentation/13.0/index.html - # Odoo在线中文用户手册(长期更新) # https://www.odooai.cn/documentation/user/10.0/zh_CN/index.html diff --git a/app_common/models/__init__.py b/app_common/models/__init__.py index 1aad5890..534ba2b7 100644 --- a/app_common/models/__init__.py +++ b/app_common/models/__init__.py @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- # Part of odooai.cn. See LICENSE file for full copyright and licensing details. -# Created on 2019-04-20 +# Created on 2023-02-02 # author: 欧度智能,http://www.odooai.cn # email: 300883@qq.com # resource of odooai @@ -26,5 +26,12 @@ from . import base from . import ir_ui_view from . import ir_cron from . import res_users +from . import ir_mail_server +from . import mail_mail +from . import ir_http +from . import app_import +from . import res_partner + + diff --git a/app_common/models/app_import.py b/app_common/models/app_import.py new file mode 100644 index 00000000..c608bc4b --- /dev/null +++ b/app_common/models/app_import.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- + +import base64 +import io +import csv +import os.path + +from odoo import api, fields, models, modules, tools, SUPERUSER_ID, _ +from odoo.tools import pycompat +from odoo.tests import common +ADMIN_USER_ID = common.ADMIN_USER_ID + +def app_quick_import(cr, content_path, sep=None): + if not sep: + sep = '/' + dir_split = content_path.split(sep) + module_name = dir_split[0] + file_name = dir_split[2] + file_path, file_type = os.path.splitext(content_path) + model_name = file_name.replace(file_type, '') + file_path = modules.get_module_resource(module_name, dir_split[1], file_name) + content = open(file_path, 'rb').read() + uid = SUPERUSER_ID + if model_name == 'mail.channel': + # todo: 创建mail.channel时,如果用root用户会报错 + uid = 2 + env = api.Environment(cr, uid, {}) + if file_type == '.csv': + file_type = 'text/csv' + elif file_type in ['.xls', '.xlsx']: + file_type = 'application/vnd.ms-excel' + import_wizard = env['base_import.import'].create({ + 'res_model': model_name, + 'file_name': file_name, + 'file_type': file_type, + 'file': content, + }) + if file_type == 'text/csv': + preview = import_wizard.parse_preview({ + 'separator': ',', + 'has_headers': True, + 'quoting': '"', + }) + elif file_type == 'application/vnd.ms-excel': + preview = import_wizard.parse_preview({ + 'has_headers': True, + }) + result = import_wizard.execute_import( + preview["headers"], + preview["headers"], + preview["options"] + ) + + diff --git a/app_common/models/base.py b/app_common/models/base.py index 26d72f9a..70472217 100644 --- a/app_common/models/base.py +++ b/app_common/models/base.py @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from odoo import models, fields, api, _ from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT +from odoo.http import request import requests import base64 @@ -65,6 +66,8 @@ class Base(models.AbstractModel): if self._context.get(fieldname) or self._context.get('default_%s' % fieldname): return self._context.get(fieldname) or self._context.get('default_%s' % fieldname) else: + if not domain: + domain = self._fields[fieldname].domain or [] rec = self.env[self._fields[fieldname].comodel_name].sudo().search(domain, limit=1) return rec.id if rec else False return False @@ -98,11 +101,60 @@ class Base(models.AbstractModel): @api.model def get_image_from_url(self, url): - if not url: - return None - try: - response = requests.get(url) # 将这个图片保存在内存 - except Exception as e: - return None # 返回这个图片的base64编码 - return base64.b64encode(BytesIO(response.content).read()) + return get_image_from_url(url) + + def get_ua_type(self): + return get_ua_type() + +def get_image_from_url(url): + if not url: + return None + try: + response = requests.get(url, timeout=5) + except Exception as e: + return None + # 返回这个图片的base64编码 + return base64.b64encode(BytesIO(response.content).read()) + +def get_ua_type(): + ua = request.httprequest.headers.get('User-Agent') + # 临时用 agent 处理,后续要前端中正确处理或者都从后台来 + # 微信浏览器 + # MicroMessenger: Mozilla/5.0 (Linux; Android 10; ELE-AL00 Build/HUAWEIELE-AL00; wv) + # AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/77.0.3865.120 + # MQQBrowser/6.2 TBS/045525 Mobile Safari/537.36 MMWEBID/3135 MicroMessenger/8.0.2.1860(0x2800023B) Process/tools WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 + # 微信浏览器,开发工具,网页 iphone + # ,Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 + # wechatdevtools/1.03.2011120 MicroMessenger/7.0.4 Language/zh_CN webview/16178807094901773 + # webdebugger port/27772 token/b91f4a234b918f4e2a5d1a835a09c31e + + # 微信小程序 + # MicroMessenger: Mozilla/5.0 (Linux; Android 10; ELE-AL00 Build/HUAWEIELE-AL00; wv) + # AppleWebKit/537.36 (KHTML, like Gecko) Version/4.0 Chrome/78.0.3904.62 XWEB/2767 MMWEBSDK/20210302 Mobile Safari/537.36 MMWEBID/6689 MicroMessenger/8.0.2.1860(0x2800023B) Process/appbrand2 WeChat/arm64 Weixin NetType/WIFI Language/zh_CN ABI/arm64 + # MiniProgramEnv/android + # 'Mozilla/5.0 (iPhone; CPU iPhone OS 15_7_5 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 MicroMessenger/8.0.37(0x18002529) NetType/WIFI Language/zh_CN' + # 微信浏览器,开发工具,小程序,iphone + # Mozilla/5.0 (iPhone; CPU iPhone OS 11_0 like Mac OS X) AppleWebKit/604.1.38 (KHTML, like Gecko) Version/11.0 Mobile/15A372 Safari/604.1 + # wechatdevtools/1.03.2011120 MicroMessenger/7.0.4 Language/zh_CN webview/ + # 微信内,iphone web + # Mozilla/5.0 (iPhone; CPU iPhone OS 14_4_2 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Mobile/15E148 + # MicroMessenger/8.0.3(0x1800032a) NetType/WIFI Language/zh_CN + # 安卓app,h5 + # ELE-AL00(Android/10) (cn.erpapp.o20sticks.App/13.20.12.09) Weex/0.26.0 1080x2265 + + # web 表示普通浏览器,后续更深入处理 + utype = 'web' + # todo: 引入现成 py lib,处理企业微信 + if 'MicroMessenger' in ua and 'webdebugger' not in ua \ + and ('miniProgram' in ua or 'MiniProgram' in ua or 'MiniProgramEnv' in ua or 'wechatdevtools' in ua): + # 微信小程序及开发者工具 + utype = 'wxapp' + elif 'MicroMessenger' in ua: + # 微信浏览器 + utype = 'wxweb' + elif 'cn.erpapp.o20sticks.App' in ua: + # 安卓app + utype = 'native_android' + # _logger.warning('=========get ua %s,%s' % (utype, ua)) + return utype diff --git a/app_common/models/ir_http.py b/app_common/models/ir_http.py new file mode 100644 index 00000000..565d83ed --- /dev/null +++ b/app_common/models/ir_http.py @@ -0,0 +1,17 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + + +from odoo import models +from odoo.http import request + + +class IrHttp(models.AbstractModel): + _inherit = 'ir.http' + + def session_info(self): + result = super(IrHttp, self).session_info() + result['ua_type'] = self.get_ua_type() + return result + + diff --git a/app_common/models/ir_mail_server.py b/app_common/models/ir_mail_server.py new file mode 100644 index 00000000..1f665086 --- /dev/null +++ b/app_common/models/ir_mail_server.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ + +import logging +_logger = logging.getLogger(__name__) + +class IrMailServer(models.Model): + _inherit = "ir.mail_server" + _order = "sequence" + + # 改默认发邮件逻辑 + @api.model + def send_email(self, message, mail_server_id=None, smtp_server=None, smtp_port=None, + smtp_user=None, smtp_password=None, smtp_encryption=None, smtp_debug=False, + smtp_session=None): + + email_to = message['To'] + + # 忽略掉无效email,避免被ban + if email_to.find('no-reply@odooai.cn') != -1 or email_to.find('postmaster-odoo@odooai.cn') != -1: + pass + elif email_to.find('example.com') != -1 or email_to.find('@sunpop.cn') != -1 or email_to.find('@odooapp.cn') != -1: + _logger.error(_("=================Email to ignore: %s") % email_to) + raise AssertionError(_("Email to ignore: %s") % email_to) + + return super(IrMailServer, self).send_email(message, mail_server_id, smtp_server, smtp_port, + smtp_user, smtp_password, smtp_encryption, smtp_debug, + smtp_session) diff --git a/app_common/models/ir_ui_view.py b/app_common/models/ir_ui_view.py index a1e5e1c0..1ba89d75 100644 --- a/app_common/models/ir_ui_view.py +++ b/app_common/models/ir_ui_view.py @@ -32,8 +32,9 @@ view_validation.relaxng = app_relaxng class View(models.Model): _inherit = 'ir.ui.view' - def __init__(self, *args, **kwargs): - super(View, self).__init__(*args, **kwargs) + def __init__(self, env, ids, prefetch_ids): + # 这里应该是无必要,但为了更安全 + super(View, self).__init__(env, ids, prefetch_ids) view_validation.relaxng = app_relaxng # todo: 有可能需要处理增加的 header等标签 diff --git a/app_common/models/mail_mail.py b/app_common/models/mail_mail.py new file mode 100644 index 00000000..34e4de5b --- /dev/null +++ b/app_common/models/mail_mail.py @@ -0,0 +1,16 @@ +# -*- coding: utf-8 -*- + +from odoo import api, fields, models, _ + +import logging +_logger = logging.getLogger(__name__) + +class MailMail(models.Model): + _inherit = "mail.mail" + + # 猴子补丁模式,改默认发邮件逻辑 + def _send(self, auto_commit=False, raise_exception=False, smtp_session=None): + for m in self: + if m.email_to and (m.email_to.find('example.com') != -1 or m.email_to.find('@odooai.cn') != -1 or m.email_to.find('@odooapp.cn') != -1): + self = self - m + return super(MailMail, self)._send(auto_commit, raise_exception, smtp_session) diff --git a/app_common/models/res_partner.py b/app_common/models/res_partner.py new file mode 100644 index 00000000..e0a087bc --- /dev/null +++ b/app_common/models/res_partner.py @@ -0,0 +1,13 @@ +# -*- coding: utf-8 -*- +# Part of Odoo. See LICENSE file for full copyright and licensing details. + +from odoo import api, fields, models, tools, _ + + +class ResPartner(models.Model): + _inherit = 'res.partner' + + def get_related_user_id(self): + self.ensure_one() + user = self.env['res.users'].sudo().with_context(active_test=False).search([('partner_id', '=', self.id)], limit=1) + return user diff --git a/app_common/rng/common.rng b/app_common/rng/common.rng index 7564b0f3..9c422d38 100644 --- a/app_common/rng/common.rng +++ b/app_common/rng/common.rng @@ -278,6 +278,16 @@ + + + + + + + + + + @@ -415,7 +425,8 @@ - + + @@ -425,6 +436,7 @@ + diff --git a/app_common/rng/search_view.rng b/app_common/rng/search_view.rng index d1025251..3f3c711f 100644 --- a/app_common/rng/search_view.rng +++ b/app_common/rng/search_view.rng @@ -13,6 +13,7 @@ + diff --git a/app_common/rng/tree_view.rng b/app_common/rng/tree_view.rng index fd800c55..25d48922 100644 --- a/app_common/rng/tree_view.rng +++ b/app_common/rng/tree_view.rng @@ -58,11 +58,18 @@ + + + + + + + diff --git a/app_common/static/description/index.html b/app_common/static/description/index.html index 3e8119a8..5098b556 100644 --- a/app_common/static/description/index.html +++ b/app_common/static/description/index.html @@ -1,11 +1,11 @@ -
+
-
+

-

Lastest update: v15.21.11.30

-
+

Lastest update: v15.23.09.28

+
@@ -26,7 +26,7 @@
  • - 5. Support Odoo 15, 14, 13, 12, 11, Enterprise and Community Edition. + 5. Support Odoo 16, 15, 14, 13, 12, 11, Enterprise and Community Edition.
  • @@ -36,9 +36,9 @@
    -
    +
    -

    Setup, please run the follow command to install the lib.

    +

    Setup, please run the follow command to install the lib.

    pip install pyyaml ua-parser user-agents

    @@ -47,9 +47,9 @@
    -
    +
    -

    So Easy to navigator and search any data.

    +

    So Easy to navigator and search any data.

    @@ -57,9 +57,9 @@
    -
    +
    -

    Multi-language Support..

    +

    Multi-language Support..

    @@ -67,9 +67,9 @@
    -
    +
    -
    +

    Technical Help & Support

    @@ -95,9 +95,9 @@
    -

    More Powerful addons, Make your odoo very easy to use, easy customize: - Supop.cn Odoo Addons -

    +

    More Powerful addons, Make your odoo very easy to use, easy customize: + odooai.cn Odoo Addons +