diff --git a/CHANGELOG b/CHANGELOG index 234e996824..03b034e1b3 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,4 @@ +* Allow copying attachments and notes to created records * Add link button on form * Support explicit delete and remove for saving and on_change xxx2Many * Add export_data_domain to ModelStorage diff --git a/trytond/ir/attachment.py b/trytond/ir/attachment.py index 2061228998..f0b6ca499b 100644 --- a/trytond/ir/attachment.py +++ b/trytond/ir/attachment.py @@ -3,15 +3,14 @@ from sql import Null from sql.operators import Concat +from trytond.i18n import lazy_gettext from ..model import ModelView, ModelSQL, fields from ..transaction import Transaction from ..pyson import Eval -from .resource import ResourceMixin +from .resource import ResourceMixin, resource_copy from ..config import config -__all__ = [ - 'Attachment', - ] +__all__ = ['AttachmentCopyMixin'] def firstline(description): @@ -102,3 +101,10 @@ class Attachment(ResourceMixin, ModelSQL, ModelView): @fields.depends('description') def on_change_with_summary(self, name=None): return firstline(self.description or '') + + +class AttachmentCopyMixin( + resource_copy( + 'ir.attachment', 'attachments', + lazy_gettext('ir.msg_attachments'))): + pass diff --git a/trytond/ir/message.xml b/trytond/ir/message.xml index b252a7357b..653c20c303 100644 --- a/trytond/ir/message.xml +++ b/trytond/ir/message.xml @@ -302,5 +302,14 @@ this repository contains the full copyright notices and license terms. --> s + + The resources to which this record must be copied. + + + Attachments + + + Notes + diff --git a/trytond/ir/note.py b/trytond/ir/note.py index 8f988f195a..4b821bdaa0 100644 --- a/trytond/ir/note.py +++ b/trytond/ir/note.py @@ -5,14 +5,15 @@ from textwrap import TextWrapper from sql import Null from sql.conditionals import Case +from trytond.i18n import lazy_gettext from ..model import ModelView, ModelSQL, ModelStorage, fields from ..pool import Pool from ..transaction import Transaction from ..tools import grouped_slice, reduce_ids from ..pyson import Eval -from .resource import ResourceMixin +from .resource import ResourceMixin, resource_copy -__all__ = ['Note', 'NoteRead'] +__all__ = ['NoteCopyMixin'] class Note(ResourceMixin, ModelSQL, ModelView): @@ -115,3 +116,8 @@ class NoteRead(ModelSQL): ondelete='CASCADE') user = fields.Many2One('res.user', 'User', required=True, ondelete='CASCADE') + + +class NoteCopyMixin( + resource_copy('ir.note', 'notes', lazy_gettext('ir.msg_notes'))): + pass diff --git a/trytond/ir/resource.py b/trytond/ir/resource.py index 4aaac956ff..c903dad04c 100644 --- a/trytond/ir/resource.py +++ b/trytond/ir/resource.py @@ -2,18 +2,28 @@ # this repository contains the full copyright notices and license terms. from sql.conditionals import Coalesce -from ..model import ModelSQL, ModelView, fields +from trytond.i18n import lazy_gettext +from ..model import ModelStorage, ModelView, fields from ..pool import Pool from ..transaction import Transaction from ..pyson import Eval -__all__ = ['ResourceMixin'] +__all__ = ['ResourceMixin', 'resource_copy'] -class ResourceMixin(ModelSQL, ModelView): +class ResourceMixin(ModelStorage, ModelView): resource = fields.Reference('Resource', selection='get_models', required=True, select=True) + copy_to_resources = fields.MultiSelection( + 'get_copy_to_resources', "Copy to Resources", + states={ + 'invisible': ~Eval('copy_to_resources_visible'), + }, + depends=['copy_to_resources_visible']) + copy_to_resources_visible = fields.Function( + fields.Boolean("Copy to Resources Visible"), + 'on_change_with_copy_to_resources_visible') last_user = fields.Function(fields.Char('Last User', states={ 'invisible': ~Eval('last_user'), @@ -43,6 +53,24 @@ class ResourceMixin(ModelSQL, ModelView): access = ModelAccess.get_access([m.model for m in models]) return [(m.model, m.name) for m in models if access[m.model]['read']] + @fields.depends('resource') + def get_copy_to_resources(self): + pool = Pool() + Model = pool.get('ir.model') + resources = [] + if isinstance(self.resource, ResourceCopyMixin): + models = self.resource.get_resources_to_copy(self.__name__) + if models: + models = Model.search([ + ('model', 'in', models), + ]) + resources.extend((m.model, m.name) for m in models) + return resources + + @fields.depends(methods=['get_copy_to_resources']) + def on_change_with_copy_to_resources_visible(self, name=None): + return bool(self.get_copy_to_resources()) + def get_last_user(self, name): return (self.write_uid.rec_name if self.write_uid else self.create_uid.rec_name) @@ -103,3 +131,49 @@ class ResourceMixin(ModelSQL, ModelView): records = super(ResourceMixin, cls).create(vlist) cls.check_access([r.id for r in records], mode='create') return records + + +class ResourceCopyMixin(ModelStorage): + + @classmethod + def get_resources_to_copy(cls, name): + return set() + + +def resource_copy(resource, name, string): + + class _ResourceCopyMixin(ResourceCopyMixin): + + @classmethod + def copy(cls, records, default=None): + if default is None: + default = {} + else: + default = default.copy() + default.setdefault(name, None) + return super().copy(records, default=default) + + def copy_resources_to(self, target): + pool = Pool() + Resource = pool.get(resource) + + try: + super().copy_resources_to(target) + except AttributeError: + pass + + to_copy = [] + for record in getattr(self, name): + if (record.copy_to_resources + and target.__name__ in record.copy_to_resources): + to_copy.append(record) + if to_copy: + return Resource.copy(to_copy, default={ + 'resource': str(target), + 'copy_to_resources': None, + }) + + setattr(_ResourceCopyMixin, name, fields.One2Many( + resource, 'resource', string, + help=lazy_gettext('ir.msg_resource_copy_help'))) + return _ResourceCopyMixin diff --git a/trytond/ir/view/attachment_form.xml b/trytond/ir/view/attachment_form.xml index 0a14e6e46f..a393ef19f0 100644 --- a/trytond/ir/view/attachment_form.xml +++ b/trytond/ir/view/attachment_form.xml @@ -16,6 +16,8 @@ this repository contains the full copyright notices and license terms. -->