Initial import from Docker volume
This commit is contained in:
244
model/dictschema.py
Executable file
244
model/dictschema.py
Executable file
@@ -0,0 +1,244 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the toplevel of this
|
||||
# repository contains the full copyright notices and license terms.
|
||||
import json
|
||||
from collections import OrderedDict
|
||||
|
||||
from trytond.cache import Cache
|
||||
from trytond.config import config
|
||||
from trytond.i18n import gettext, lazy_gettext
|
||||
from trytond.model import fields
|
||||
from trytond.model.exceptions import ValidationError
|
||||
from trytond.pool import Pool
|
||||
from trytond.pyson import Eval, PYSONDecoder
|
||||
from trytond.rpc import RPC
|
||||
from trytond.tools import slugify
|
||||
from trytond.transaction import Transaction
|
||||
|
||||
|
||||
class DomainError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class SelectionError(ValidationError):
|
||||
pass
|
||||
|
||||
|
||||
class DictSchemaMixin(object):
|
||||
__slots__ = ()
|
||||
_rec_name = 'string'
|
||||
name = fields.Char(lazy_gettext('ir.msg_dict_schema_name'), required=True)
|
||||
string = fields.Char(
|
||||
lazy_gettext('ir.msg_dict_schema_string'),
|
||||
translate=True, required=True)
|
||||
help = fields.Text(
|
||||
lazy_gettext('ir.msg_dict_schema_help'),
|
||||
translate=True)
|
||||
type_ = fields.Selection([
|
||||
('boolean', lazy_gettext('ir.msg_dict_schema_boolean')),
|
||||
('integer', lazy_gettext('ir.msg_dict_schema_integer')),
|
||||
('char', lazy_gettext('ir.msg_dict_schema_char')),
|
||||
('float', lazy_gettext('ir.msg_dict_schema_float')),
|
||||
('numeric', lazy_gettext('ir.msg_dict_schema_numeric')),
|
||||
('date', lazy_gettext('ir.msg_dict_schema_date')),
|
||||
('datetime', lazy_gettext('ir.msg_dict_schema_datetime')),
|
||||
('selection', lazy_gettext('ir.msg_dict_schema_selection')),
|
||||
('multiselection',
|
||||
lazy_gettext('ir.msg_dict_schema_multiselection')),
|
||||
], lazy_gettext('ir.msg_dict_schema_type'), required=True)
|
||||
digits = fields.Integer(
|
||||
lazy_gettext('ir.msg_dict_schema_digits'),
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(['float', 'numeric']),
|
||||
}, depends=['type_'])
|
||||
domain = fields.Char(lazy_gettext('ir.msg_dict_schema_domain'))
|
||||
selection = fields.Text(
|
||||
lazy_gettext('ir.msg_dict_schema_selection'),
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(['selection', 'multiselection']),
|
||||
}, translate=True, depends=['type_'],
|
||||
help=lazy_gettext('ir.msg_dict_schema_selection_help'))
|
||||
selection_sorted = fields.Boolean(
|
||||
lazy_gettext('ir.msg_dict_schema_selection_sorted'),
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(['selection', 'multiselection']),
|
||||
}, depends=['type_'],
|
||||
help=lazy_gettext('ir.msg_dict_schema_selection_sorted_help'))
|
||||
help_selection = fields.Text(
|
||||
lazy_gettext('ir.msg_dict_schema_help_selection'), translate=True,
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(['selection', 'multiselection']),
|
||||
},
|
||||
depends=['type_'],
|
||||
help=lazy_gettext('ir.msg_dict_schema_help_selection_help'))
|
||||
selection_json = fields.Function(fields.Char(
|
||||
lazy_gettext('ir.msg_dict_schema_selection_json'),
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(
|
||||
['selection', 'multiselection']),
|
||||
},
|
||||
depends=['type_']), 'get_selection_json')
|
||||
help_selection_json = fields.Function(fields.Char(
|
||||
lazy_gettext('ir.msg_dict_schema_help_selection_json'),
|
||||
states={
|
||||
'invisible': ~Eval('type_').in_(
|
||||
['selection', 'multiselection']),
|
||||
},
|
||||
depends=['type_']), 'get_selection_json')
|
||||
_relation_fields_cache = Cache('_dict_schema_mixin.get_relation_fields')
|
||||
|
||||
@classmethod
|
||||
def __setup__(cls):
|
||||
super(DictSchemaMixin, cls).__setup__()
|
||||
cls.__rpc__.update({
|
||||
'get_keys': RPC(instantiate=0),
|
||||
'search_get_keys': RPC(),
|
||||
})
|
||||
|
||||
@staticmethod
|
||||
def default_digits():
|
||||
return 2
|
||||
|
||||
@staticmethod
|
||||
def default_selection_sorted():
|
||||
return True
|
||||
|
||||
@fields.depends('name', 'string')
|
||||
def on_change_string(self):
|
||||
if not self.name and self.string:
|
||||
self.name = slugify(self.string.lower(), hyphenate='_')
|
||||
|
||||
@classmethod
|
||||
def validate_fields(cls, schemas, field_names):
|
||||
super().validate_fields(schemas, field_names)
|
||||
cls.check_domain(schemas, field_names)
|
||||
cls.check_selection(schemas, field_names)
|
||||
|
||||
@classmethod
|
||||
def check_domain(cls, schemas, field_names=None):
|
||||
if field_names and 'domain' not in field_names:
|
||||
return
|
||||
for schema in schemas:
|
||||
if not schema.domain:
|
||||
continue
|
||||
try:
|
||||
value = PYSONDecoder().decode(schema.domain)
|
||||
except Exception:
|
||||
raise DomainError(
|
||||
gettext('ir.msg_dict_schema_invalid_domain',
|
||||
schema=schema.rec_name))
|
||||
if not isinstance(value, list):
|
||||
raise DomainError(
|
||||
gettext('ir.msg_dict_schema_invalid_domain',
|
||||
schema=schema.rec_name))
|
||||
|
||||
@classmethod
|
||||
def check_selection(cls, schemas, field_names=None):
|
||||
if field_names and not (field_names & {
|
||||
'type_', 'selection', 'help_selection'}):
|
||||
return
|
||||
for schema in schemas:
|
||||
if schema.type_ not in {'selection', 'multiselection'}:
|
||||
continue
|
||||
for name in ['selection', 'help_selection']:
|
||||
try:
|
||||
dict(json.loads(schema.get_selection_json(name + '_json')))
|
||||
except Exception:
|
||||
raise SelectionError(
|
||||
gettext('ir.msg_dict_schema_invalid_%s' % name,
|
||||
schema=schema.rec_name))
|
||||
|
||||
def get_selection_json(self, name):
|
||||
field = name[:-len('_json')]
|
||||
db_selection = getattr(self, field) or ''
|
||||
selection = [[w.strip() for w in v.split(':', 1)]
|
||||
for v in db_selection.splitlines() if v]
|
||||
return json.dumps(selection, separators=(',', ':'))
|
||||
|
||||
@classmethod
|
||||
def get_keys(cls, records):
|
||||
pool = Pool()
|
||||
Config = pool.get('ir.configuration')
|
||||
keys = []
|
||||
for record in records:
|
||||
new_key = {
|
||||
'id': record.id,
|
||||
'name': record.name,
|
||||
'string': record.string,
|
||||
'help': record.help,
|
||||
'type': record.type_,
|
||||
'domain': record.domain,
|
||||
'sequence': getattr(record, 'sequence', record.name),
|
||||
}
|
||||
if record.type_ in {'selection', 'multiselection'}:
|
||||
with Transaction().set_context(language=Config.get_language()):
|
||||
english_key = cls(record.id)
|
||||
selection = OrderedDict(json.loads(
|
||||
english_key.selection_json))
|
||||
selection.update(dict(json.loads(record.selection_json)))
|
||||
new_key['selection'] = list(selection.items())
|
||||
new_key['help_selection'] = dict(
|
||||
json.loads(record.help_selection_json))
|
||||
new_key['sort'] = record.selection_sorted
|
||||
elif record.type_ in ('float', 'numeric'):
|
||||
new_key['digits'] = (16, record.digits)
|
||||
keys.append(new_key)
|
||||
return keys
|
||||
|
||||
@classmethod
|
||||
def search_get_keys(cls, domain, limit=None):
|
||||
schemas = cls.search(domain, limit=limit)
|
||||
return cls.get_keys(schemas)
|
||||
|
||||
@classmethod
|
||||
def get_relation_fields(cls):
|
||||
if not config.get('dict', cls.__name__, default=True):
|
||||
return {}
|
||||
fields = cls._relation_fields_cache.get(cls.__name__)
|
||||
if fields is not None:
|
||||
return fields
|
||||
keys = cls.get_keys(cls.search([]))
|
||||
fields = {k['name']: k for k in keys}
|
||||
cls._relation_fields_cache.set(cls.__name__, fields)
|
||||
return fields
|
||||
|
||||
@classmethod
|
||||
def create(cls, vlist):
|
||||
records = super().create(vlist)
|
||||
cls._relation_fields_cache.clear()
|
||||
return records
|
||||
|
||||
@classmethod
|
||||
def write(cls, *args):
|
||||
super().write(*args)
|
||||
cls._relation_fields_cache.clear()
|
||||
|
||||
@classmethod
|
||||
def delete(cls, records):
|
||||
super().delete(records)
|
||||
cls._relation_fields_cache.clear()
|
||||
|
||||
def format(self, value, lang=None):
|
||||
pool = Pool()
|
||||
Lang = pool.get('ir.lang')
|
||||
if lang is None:
|
||||
lang = Lang.get()
|
||||
if value is None:
|
||||
return ''
|
||||
if self.type_ == 'boolean':
|
||||
if value:
|
||||
return gettext('ir.msg_dict_yes')
|
||||
else:
|
||||
return gettext('ir.msg_dict_no')
|
||||
elif self.type_ == 'integer':
|
||||
return lang.format('%i', value)
|
||||
elif self.type_ in {'float', 'numeric'}:
|
||||
return lang.format('%.*f', (self.digits, value))
|
||||
elif self.type_ in {'date', 'datetime'}:
|
||||
return lang.strftime(value)
|
||||
elif self.type_ in {'selection', 'multiselection'}:
|
||||
values = dict(json.loads(self.selection_json))
|
||||
if self.type_ == 'selection':
|
||||
return values.get(value, '')
|
||||
else:
|
||||
return "; ".join(values.get(v, '') for v in value)
|
||||
return value
|
||||
Reference in New Issue
Block a user