mirror of
https://github.com/guohuadeng/app-odoo.git
synced 2025-02-23 04:11:36 +02:00
opt m2o
This commit is contained in:
@@ -23,3 +23,7 @@
|
||||
# description:
|
||||
|
||||
from . import base
|
||||
# from . import fields
|
||||
# from . import validator
|
||||
# from . import ir_ui_view
|
||||
|
||||
|
||||
@@ -1,6 +1,9 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT, DEFAULT_SERVER_DATETIME_FORMAT
|
||||
|
||||
from datetime import date, datetime, time
|
||||
import pytz
|
||||
|
||||
class Base(models.AbstractModel):
|
||||
_inherit = 'base'
|
||||
@@ -14,3 +17,29 @@ class Base(models.AbstractModel):
|
||||
rec = self.env[self._fields[fieldname].comodel_name].search(domain, limit=1)
|
||||
return rec.id if rec else False
|
||||
return False
|
||||
|
||||
def _app_dt2local(self, value, return_format=DEFAULT_SERVER_DATETIME_FORMAT):
|
||||
"""
|
||||
将value中时间,按格式转为用户本地时间
|
||||
"""
|
||||
if not value:
|
||||
return value
|
||||
if isinstance(value, datetime):
|
||||
value = value.strftime(return_format)
|
||||
dt = datetime.strptime(value, return_format)
|
||||
pytz_timezone = pytz.timezone(self.env.user.tz or 'Etc/GMT-8')
|
||||
dt = dt.replace(tzinfo=pytz.timezone('UTC'))
|
||||
return dt.astimezone(pytz_timezone).strftime(return_format)
|
||||
|
||||
def _app_dt2utc(self, value, return_format=DEFAULT_SERVER_DATETIME_FORMAT):
|
||||
"""
|
||||
将value中用户本地时间,按格式转为UTC时间,输出 str
|
||||
"""
|
||||
if not value:
|
||||
return value
|
||||
if isinstance(value, datetime):
|
||||
value = value.strftime(return_format)
|
||||
dt = datetime.strptime(value, return_format)
|
||||
user_tz = pytz.timezone(self.env.user.tz or 'Etc/GMT+8')
|
||||
dt = dt.replace(tzinfo=pytz.timezone('UTC'))
|
||||
return dt.astimezone(user_tz).strftime(return_format)
|
||||
|
||||
49
app_common/models/fields.py
Normal file
49
app_common/models/fields.py
Normal file
@@ -0,0 +1,49 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo.fields import Field, resolve_mro
|
||||
from odoo.fields import Selection as oldSelection
|
||||
from odoo.tools import merge_sequences
|
||||
import logging
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
# 此处用猴子补丁,热更新,不影响后续继承
|
||||
class Selection(Field):
|
||||
def _setup_attrs_app(self, model, name):
|
||||
Field._setup_attrs(self, model, name)
|
||||
|
||||
# determine selection (applying 'selection_add' extensions)
|
||||
values = None
|
||||
labels = {}
|
||||
|
||||
for field in reversed(resolve_mro(model, name, self._can_setup_from)):
|
||||
# We cannot use field.selection or field.selection_add here
|
||||
# because those attributes are overridden by ``_setup_attrs``.
|
||||
if 'selection' in field.args:
|
||||
selection = field.args['selection']
|
||||
if isinstance(selection, list):
|
||||
if (
|
||||
values is not None
|
||||
and values != [kv[0] for kv in selection]
|
||||
):
|
||||
_logger.debug("%s: selection=%r overrides existing selection; use selection_add instead", self, selection)
|
||||
values = [kv[0] for kv in selection]
|
||||
labels = dict(selection)
|
||||
else:
|
||||
self.selection = selection
|
||||
values = None
|
||||
labels = {}
|
||||
|
||||
if 'selection_add' in field.args:
|
||||
selection_add = field.args['selection_add']
|
||||
assert isinstance(selection_add, list), \
|
||||
"%s: selection_add=%r must be a list" % (self, selection_add)
|
||||
assert values is not None, \
|
||||
"%s: selection_add=%r on non-list selection %r" % (self, selection_add, self.selection)
|
||||
values = merge_sequences(values, [kv[0] for kv in selection_add])
|
||||
labels.update(kv for kv in selection_add if len(kv) == 2)
|
||||
|
||||
if values is not None:
|
||||
self.selection = [(value, labels[value]) for value in values]
|
||||
|
||||
oldSelection._setup_attrs = Selection._setup_attrs_app
|
||||
66
app_common/models/ir_ui_view.py
Normal file
66
app_common/models/ir_ui_view.py
Normal file
@@ -0,0 +1,66 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import api, models, tools, SUPERUSER_ID
|
||||
from odoo.modules.module import get_resource_path
|
||||
from odoo.tools import view_validation
|
||||
from odoo.tools.view_validation import _relaxng_cache, validate, _validators
|
||||
from odoo.tools.safe_eval import safe_eval
|
||||
|
||||
from lxml import etree
|
||||
import logging
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@validate('tree')
|
||||
def app_valid_field_in_tree(arch, **kwargs):
|
||||
# 增加 header
|
||||
return all(
|
||||
child.tag in ('field', 'button', 'control', 'groupby', 'header')
|
||||
for child in arch.xpath('/tree/*')
|
||||
)
|
||||
|
||||
def app_relaxng(view_type):
|
||||
""" Return a validator for the given view type, or None. """
|
||||
if view_type not in _relaxng_cache:
|
||||
# tree, search 特殊
|
||||
if view_type in ['tree', 'search']:
|
||||
_file = get_resource_path('app_common', 'rng', '%s_view.rng' % view_type)
|
||||
else:
|
||||
_file = get_resource_path('base', 'rng', '%s_view.rng' % view_type)
|
||||
with tools.file_open(_file) as frng:
|
||||
try:
|
||||
relaxng_doc = etree.parse(frng)
|
||||
_relaxng_cache[view_type] = etree.RelaxNG(relaxng_doc)
|
||||
except Exception:
|
||||
_logger.exception('Failed to load RelaxNG XML schema for views validation')
|
||||
_relaxng_cache[view_type] = None
|
||||
return _relaxng_cache[view_type]
|
||||
|
||||
def app_reset_valid_view(view_type):
|
||||
_relaxng_cache = view_validation._relaxng_cache
|
||||
for pred in _validators[view_type]:
|
||||
# 要pop掉函数 valid_field_in_tree
|
||||
if pred.__name__ == 'valid_field_in_tree':
|
||||
_validators[view_type].remove(pred)
|
||||
try:
|
||||
_relaxng_cache.pop(view_type, None)
|
||||
_relaxng_cache[view_type] = None
|
||||
except Exception:
|
||||
pass
|
||||
_relaxng_cache[view_type] = app_relaxng(view_type)
|
||||
|
||||
app_reset_valid_view('tree')
|
||||
view_validation.valid_field_in_tree = app_valid_field_in_tree
|
||||
view_validation.relaxng = app_relaxng
|
||||
|
||||
class View(models.Model):
|
||||
_inherit = 'ir.ui.view'
|
||||
|
||||
def __init__(self, *args, **kwargs):
|
||||
super(View, self).__init__(*args, **kwargs)
|
||||
view_validation.relaxng = app_relaxng
|
||||
# 重置 tree
|
||||
app_reset_valid_view('tree')
|
||||
|
||||
# todo: 有可能需要处理增加的 header等标签
|
||||
# 直接重写原生方法
|
||||
# def transfer_node_to_modifiers(node, modifiers, context=None, in_tree_view=False):
|
||||
78
app_common/models/validator_old.py
Normal file
78
app_common/models/validator_old.py
Normal file
@@ -0,0 +1,78 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from odoo import tools, _
|
||||
from odoo.modules.module import get_resource_path
|
||||
from odoo.tools import view_validation
|
||||
from odoo.tools.view_validation import validate, _validators
|
||||
from lxml import etree
|
||||
import logging
|
||||
|
||||
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
_relaxng_cache = view_validation._relaxng_cache
|
||||
_relaxng_cache['tree'] = None
|
||||
with tools.file_open(get_resource_path('app_common', 'rng', 'tree_view.rng')) as frng:
|
||||
try:
|
||||
text = frng.read()
|
||||
# with tools.file_open('addons/base/rng/common.rng') as common_rng:
|
||||
# common_txt = common_rng.read()
|
||||
# start_pos = common_txt.find('<rng:grammar')
|
||||
# start_pos = common_txt.find('>', start_pos)
|
||||
# end_pos = common_txt.find('</rng:grammar>')
|
||||
# common_content = common_txt[start_pos + 1: end_pos]
|
||||
#
|
||||
# # 从14中学习,最新 common
|
||||
# # <rng:optional><rng:attribute name="kanban_view_ref" />
|
||||
# old_content = '''
|
||||
# <rng:optional><rng:attribute name="kanban_view_ref" /></rng:optional>
|
||||
# '''
|
||||
# new_content = '''
|
||||
# <rng:optional><rng:attribute name="hierarchize"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="expand"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="enable_counters"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="limit"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-bf"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-it"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-danger"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-info"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-muted"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-primary"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-success"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="decoration-warning"/></rng:optional>
|
||||
# <rng:optional><rng:attribute name="kanban_view_ref" /></rng:optional>
|
||||
# '''
|
||||
# common_content = common_content.replace(old_content, new_content)
|
||||
# # common 替代
|
||||
# text = text.replace('<rng:include href=\"common.rng\"/>', common_content)
|
||||
# # tree 替代
|
||||
# old_content = '''<rng:ref name="control"/>'''
|
||||
# new_content = '''<rng:element name="header">
|
||||
# <rng:zeroOrMore>
|
||||
# <rng:ref name="button"/>
|
||||
# </rng:zeroOrMore>
|
||||
# </rng:element>
|
||||
# <rng:ref name="control"/>'''
|
||||
# text = text.replace(old_content, new_content)
|
||||
# # 增加 fx_tree_table 支持
|
||||
# text = text.replace('<rng:optional><rng:attribute name=\"js_class\"/></rng:optional>',
|
||||
# '<rng:optional><rng:attribute name=\"js_class\"/></rng:optional><rng:optional><rng:attribute name=\"options\"/></rng:optional>')
|
||||
|
||||
tmp_doc = etree.fromstring(text.encode('utf-8'))
|
||||
_relaxng_cache['tree'] = etree.RelaxNG(tmp_doc)
|
||||
_logger.warning('=========new tree done: %s' % _relaxng_cache['tree'])
|
||||
except Exception as error:
|
||||
_logger.exception('Failed to load RelaxNG XML schema for views validation, {error}'.format(
|
||||
error=error))
|
||||
_relaxng_cache['tree'] = None
|
||||
|
||||
|
||||
@validate('tree')
|
||||
def app_valid_field_in_tree(arch, **kwargs):
|
||||
# 增加 header
|
||||
return all(
|
||||
child.tag in ('field', 'button', 'control', 'groupby', 'header')
|
||||
for child in arch.xpath('/tree/*')
|
||||
)
|
||||
|
||||
view_validation.valid_field_in_tree = app_valid_field_in_tree
|
||||
Reference in New Issue
Block a user