source: main/branches/3D/openPLM/plmapp/controllers/part.py @ 595

Revision 595, 13.6 KB checked in by pcosquer, 8 years ago (diff)

3D branch: merge changes from trunk rev 594

Line 
1############################################################################
2# openPLM - open source PLM
3# Copyright 2010 Philippe Joulaud, Pierre Cosquer
4#
5# This file is part of openPLM.
6#
7#    openPLM is free software: you can redistribute it and/or modify
8#    it under the terms of the GNU General Public License as published by
9#    the Free Software Foundation, either version 3 of the License, or
10#    (at your option) any later version.
11#
12#    openPLM is distributed in the hope that it will be useful,
13#    but WITHOUT ANY WARRANTY; without even the implied warranty of
14#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15#    GNU General Public License for more details.
16#
17#    You should have received a copy of the GNU General Public License
18#    along with Foobar.  If not, see <http://www.gnu.org/licenses/>.
19#
20# Contact :
21#    Philippe Joulaud : ninoo.fr@gmail.com
22#    Pierre Cosquer : pierre.cosquer@insa-rennes.fr
23################################################################################
24
25"""
26"""
27
28import datetime
29from collections import namedtuple
30
31
32import openPLM.plmapp.models as models
33from openPLM.plmapp.controllers.plmobject import PLMObjectController
34from openPLM.plmapp.controllers.base import get_controller
35
36Child = namedtuple("Child", "level link")
37Parent = namedtuple("Parent", "level link")
38
39class PartController(PLMObjectController):
40    u"""
41    Controller for :class:`.Part`.
42
43    This controller adds methods to manage Parent-Child links between two
44    Parts.
45    """
46
47    def check_add_child(self, child):
48        """
49        Checks if *child"* can be added to *self*.
50        If *child* can not be added, an exception is raised.
51       
52        :param child: child to be added
53        :type child: :class:`.Part`
54       
55        :raises: :exc:`ValueError` if *child* is already a child or a parent.
56        :raises: :exc:`ValueError` if *quantity* or *order* are negative.
57        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
58            :attr:`object`.   
59        """
60        self.check_permission("owner")
61        self.check_editable()
62        if not child.is_part:
63            raise TypeError("Can not add child: not a Part")
64        # check if child is not a parent
65        if child.id == self.object.id:
66            raise ValueError("Can not add child: child is current object")
67        get_controller(child.type)(child, self._user).check_readable()
68        parents = (p.link.parent.pk for p in self.get_parents(-1))
69        if child.pk in parents:
70            raise ValueError("Can not add child %s to %s, it is a parent" %
71                                (child, self.object))
72        link = self.parentchildlink_parent.filter(child=child, end_time=None)
73        if link:
74            raise ValueError("Can not add child, %s is already a child of %s" %
75                                (child, self.object))
76
77    def can_add_child(self, child):
78        """
79        Returns True if *child* can be added to *self*.
80        """
81
82        can_add = False
83        try:
84            self.check_add_child(child)
85            can_add = True
86        except StandardError:
87            pass
88        return can_add
89
90    def add_child(self, child, quantity, order):
91        """
92        Adds *child* to *self*.
93
94        :param child: added child
95        :type child: :class:`.Part`
96        :param quantity: amount of *child*
97        :type quantity: positive float
98        :param order: order
99        :type order: positive int
100       
101        :raises: :exc:`ValueError` if *child* is already a child or a parent.
102        :raises: :exc:`ValueError` if *quantity* or *order* are negative.
103        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
104            :attr:`object`.
105        :raises: :exc:`.PermissionError` if :attr:`object` is not editable.
106        """
107
108        if isinstance(child, PLMObjectController):
109            child = child.object
110        self.check_add_child(child)
111        # check if child is not already a direct child
112        if child.pk in (c.link.child.pk for c in self.get_children(1)):
113            raise ValueError("%s is already a child of %s" % (child, self.object))
114        if order < 0 or quantity < 0:
115            raise ValueError("Quantity or order is negative")
116        # data are valid : create the link
117        link = models.ParentChildLink()
118        link.parent = self.object
119        link.child = child
120        link.quantity = quantity
121        link.order = order
122        link.save()
123        # records creation in history
124        self._save_histo(link.ACTION_NAME,
125                         "parent : %s\nchild : %s" % (self.object, child))
126
127    def delete_child(self, child):
128        u"""
129        Deletes *child* from current children and records this action in the
130        history.
131
132        .. note::
133            The link is not destroyed: its end_time is set to now.
134       
135        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
136            :attr:`object`.
137        :raises: :exc:`.PermissionError` if :attr:`object` is not editable.
138        """
139
140        self.check_permission("owner")
141        self.check_editable()
142        if isinstance(child, PLMObjectController):
143            child = child.object
144        link = self.parentchildlink_parent.get(child=child, end_time=None)
145        link.end_time = datetime.datetime.today()
146        link.save()
147        self._save_histo("Delete - %s" % link.ACTION_NAME, "child : %s" % child)
148
149    def modify_child(self, child, new_quantity, new_order):
150        """
151        Modifies information about *child*.
152
153        :param child: added child
154        :type child: :class:`.Part`
155        :param new_quantity: amount of *child*
156        :type new_quantity: positive float
157        :param new_order: order
158        :type new_order: positive int
159       
160        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
161            :attr:`object`.
162        :raises: :exc:`.PermissionError` if :attr:`object` is not editable.
163        """
164       
165        self.check_permission("owner")
166        self.check_editable()
167        if isinstance(child, PLMObjectController):
168            child = child.object
169        if new_order < 0 or new_quantity < 0:
170            raise ValueError("Quantity or order is negative")
171        link = models.ParentChildLink.objects.get(parent=self.object,
172                                                  child=child, end_time=None)
173        if link.quantity == new_quantity and link.order == new_order:
174            # do not make an update if it is useless
175            return
176        link.end_time = datetime.datetime.today()
177        link.save()
178        # make a new link
179        link2 = models.ParentChildLink(parent=self.object, child=child,
180                                       quantity=new_quantity, order=new_order)
181        details = ""
182        if link.quantity != new_quantity:
183            details += "quantity changes from %f to %f\n" % (link.quantity, new_quantity)
184        if link.order != new_order:
185            details += "order changes from %d to %d" % (link.order, new_order)
186        self._save_histo("Modify - %s" % link.ACTION_NAME, details)
187        link2.save(force_insert=True)
188
189    def get_children(self, max_level=1, current_level=1, date=None):
190        """
191        Returns a list of all children at time *date*.
192       
193        :rtype: list of :class:`Child`
194        """
195
196        if max_level != -1 and current_level > max_level:
197            return []
198        if not date:
199            links = self.parentchildlink_parent.filter(end_time__exact=None)
200        else:
201            links = self.parentchildlink_parent.filter(ctime__lt=date).exclude(end_time__lt=date)
202        res = []
203        for link in links.order_by("order", "child__reference"):
204            res.append(Child(current_level, link))
205            pc = PartController(link.child, self._user)
206            res.extend(pc.get_children(max_level, current_level + 1, date))
207        return res
208   
209    def get_parents(self, max_level=1, current_level=1, date=None):
210        """
211        Returns a list of all parents at time *date*.
212       
213        :rtype: list of :class:`Parent`
214        """
215
216        if max_level != -1 and current_level > max_level:
217            return []
218        if not date:
219            links = self.parentchildlink_child.filter(end_time__exact=None)
220        else:
221            links = self.parentchildlink_child.filter(ctime__lt=date).exclude(end_time__lt=date)
222        res = []
223        for link in links:
224            res.append(Parent(current_level, link))
225            pc = PartController(link.parent, self._user)
226            res.extend(pc.get_parents(max_level, current_level + 1, date))
227        return res
228
229    def update_children(self, formset):
230        u"""
231        Updates children informations with data from *formset*
232       
233        :param formset:
234        :type formset: a modelfactory_formset of
235                        :class:`~plmapp.forms.ModifyChildForm`
236       
237        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
238            :attr:`object`.
239        :raises: :exc:`.PermissionError` if :attr:`object` is not editable.
240        """
241
242        self.check_permission("owner")
243        self.check_editable()
244        if formset.is_valid():
245            for form in formset.forms:
246                parent = form.cleaned_data["parent"]
247                if parent.pk != self.object.pk:
248                    raise ValueError("Bad parent %s (%s expected)" % (parent, self.object))
249                delete = form.cleaned_data["delete"]
250                child = form.cleaned_data["child"]
251                if delete:
252                    self.delete_child(child)
253                else:
254                    quantity = form.cleaned_data["quantity"]
255                    order = form.cleaned_data["order"]
256                    self.modify_child(child, quantity, order)
257
258    def revise(self, new_revision):
259        # same as PLMObjectController + add children
260        new_controller = super(PartController, self).revise(new_revision)
261        for level, link in self.get_children(1):
262            new_controller.add_child(link.child, link.quantity, link.order)
263        return new_controller
264
265    def attach_to_document(self, document):
266        """
267        Links *document* (a :class:`.Document`) with
268        :attr:`~PLMObjectController.object`.
269       
270        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
271            :attr:`object`.
272        """
273       
274        self.check_attach_document(document)
275        if isinstance(document, PLMObjectController):
276            document = document.object
277        self.documentpartlink_part.create(document=document)
278        self._save_histo(models.DocumentPartLink.ACTION_NAME,
279                         "Part : %s - Document : %s" % (self.object, document))
280
281    def detach_document(self, document):
282        """
283        Delete link between *document* (a :class:`.Document`)
284        and :attr:`~PLMObjectController.object`.
285       
286        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
287            :attr:`object`.
288        """
289
290        self.check_permission("owner")
291        if isinstance(document, PLMObjectController):
292            document = document.object
293        link = self.documentpartlink_part.get(document=document)
294        link.delete()
295        self._save_histo(models.DocumentPartLink.ACTION_NAME + " - delete",
296                         "Part : %s - Document : %s" % (self.object, document))
297
298    def get_attached_documents(self):
299        """
300        Returns all :class:`.Document` attached to
301        :attr:`~PLMObjectController.object`.
302        """
303        return self.documentpartlink_part.all()
304     
305    def is_document_attached(self, document):
306        """
307        Returns True if *document* is attached to the current part.
308        """
309
310        if isinstance(document, PLMObjectController):
311            document = document.object
312        return bool(self.documentpartlink_part.filter(document=document))
313   
314    def check_attach_document(self, document):
315        self.check_permission("owner")
316        if not hasattr(document, "is_document") or not document.is_document:
317            raise TypeError("%s is not a document" % document)
318
319        if isinstance(document, PLMObjectController):
320            document.check_readable()
321            document = document.object
322        else:
323            get_controller(document.type)(document, self._user).check_readable()
324            type(self)(document, self._user).check_readable()
325        if self.is_document_attached(document):
326            raise ValueError("Document is already attached.")
327
328    def can_attach_document(self, document):
329        """
330        Returns True if *document* can be attached to the current part.
331        """
332        can_attach = False
333        try:
334            self.check_attach_document(document)
335            can_attach = True
336        except StandardError:
337            pass
338        return can_attach
339
340    def update_doc_cad(self, formset):
341        u"""
342        Updates doc_cad informations with data from *formset*
343       
344        :param formset:
345        :type formset: a modelfactory_formset of
346                        :class:`~plmapp.forms.ModifyChildForm`
347       
348        :raises: :exc:`.PermissionError` if :attr:`_user` is not the owner of
349            :attr:`object`.
350        """
351       
352        self.check_permission("owner")
353        if formset.is_valid():
354            for form in formset.forms:
355                part = form.cleaned_data["part"]
356                if part.pk != self.object.pk:
357                    raise ValueError("Bad part %s (%s expected)" % (part, self.object))
358                delete = form.cleaned_data["delete"]
359                document = form.cleaned_data["document"]
360                if delete:
361                    self.detach_document(document)
362
Note: See TracBrowser for help on using the repository browser.