Initial import from Docker volume
This commit is contained in:
92
model/fields/fmany2one.py
Executable file
92
model/fields/fmany2one.py
Executable file
@@ -0,0 +1,92 @@
|
||||
# This file is part of Tryton. The COPYRIGHT file at the top level of
|
||||
# this repository contains the full copyright notices and license terms.
|
||||
|
||||
from sql import Column, Literal
|
||||
|
||||
from trytond.pool import Pool
|
||||
from trytond.tools import grouped_slice
|
||||
|
||||
from .function import Function
|
||||
from .many2one import Many2One
|
||||
|
||||
|
||||
def fmany2one(
|
||||
name, sources, target, string="", ondelete='SET NULL', **kwargs):
|
||||
sources = sources.split(',')
|
||||
target_model, target_fields = target.split(',', 1)
|
||||
target_fields = target_fields.split(',')
|
||||
assert len(sources) == len(target_fields)
|
||||
|
||||
class Mixin:
|
||||
__slots__ = ()
|
||||
|
||||
@classmethod
|
||||
def __register__(cls, module):
|
||||
pool = Pool()
|
||||
Target = pool.get(target_model)
|
||||
table_h = cls.__table_handler__(module)
|
||||
super().__register__(module)
|
||||
table_h.add_fk(
|
||||
sources, Target._table, target_fields,
|
||||
on_delete=getattr(cls, name).ondelete)
|
||||
|
||||
@classmethod
|
||||
def getter(cls, records, name):
|
||||
pool = Pool()
|
||||
Target = pool.get(target_model)
|
||||
values = set(filter(all,
|
||||
(tuple(getattr(r, s) for s in sources) for r in records)))
|
||||
values2id = {}
|
||||
for sub_values in grouped_slice(values):
|
||||
domain = ['OR']
|
||||
for values in sub_values:
|
||||
domain.append(
|
||||
[(f, '=', v) for f, v in zip(target_fields, values)])
|
||||
targets = Target.search(domain)
|
||||
values2id.update(
|
||||
(tuple(getattr(t, f) for f in target_fields), t.id)
|
||||
for t in targets)
|
||||
return {r.id: values2id.get(
|
||||
tuple(getattr(r, s) for s in sources)) for r in records}
|
||||
|
||||
@classmethod
|
||||
def setter(cls, records, name, value):
|
||||
pool = Pool()
|
||||
Target = pool.get(target_model)
|
||||
if value:
|
||||
value = getattr(Target(value), target_fields[0])
|
||||
else:
|
||||
value = None
|
||||
cls.write(records, {sources[0]: value})
|
||||
|
||||
@classmethod
|
||||
def searcher(cls, clause, tables):
|
||||
pool = Pool()
|
||||
Target = pool.get(target_model)
|
||||
table, _ = tables[None]
|
||||
if name not in tables:
|
||||
target = Target.__table__()
|
||||
join = Literal(True)
|
||||
for source, target_field in zip(sources, target_fields):
|
||||
join &= Column(table, source) == Column(target, target_field)
|
||||
tables[name] = {
|
||||
None: (target, join),
|
||||
}
|
||||
nested = clause[0][len(name) + 1:]
|
||||
if not nested:
|
||||
if isinstance(clause[2], str):
|
||||
nested = 'rec_name'
|
||||
else:
|
||||
nested = 'id'
|
||||
domain = [(nested, *clause[1:])]
|
||||
tables, clause = Target.search_domain(
|
||||
domain, tables=tables[name])
|
||||
return clause
|
||||
|
||||
setattr(Mixin, name, Function(
|
||||
Many2One(target_model, string, ondelete=ondelete, **kwargs),
|
||||
f'get_{name}', setter=f'set_{name}'))
|
||||
setattr(Mixin, f'get_{name}', getter)
|
||||
setattr(Mixin, f'set_{name}', setter)
|
||||
setattr(Mixin, f'domain_{name}', searcher)
|
||||
return Mixin
|
||||
Reference in New Issue
Block a user