Changeset 674 in main for branches


Ignore:
Timestamp:
01/23/12 11:15:41 (8 years ago)
Author:
pcosquer
Message:

3D branch: merge changes from trunk (rev [673])

Location:
branches/3D
Files:
21 edited
5 copied

Legend:

Unmodified
Added
Removed
  • branches/3D

  • branches/3D/docs/admin/ht_1_install_server.rst

    r595 r674  
    191191    * ``chown www-data:www-data /var/django/openPLM/trunk/openPLM/media/thumbnails`` 
    192192    * ``chown www-data:www-data /var/django/openPLM/trunk/openPLM/media/navigate`` 
    193    
     193  
     194.. _search-engine: 
     195 
    194196Configure the search engine 
    195197============================= 
     
    203205    * ``./manage.py rebuild_index`` 
    204206    * ``chown www-data:www-data -R /var/openPLM/xapian_index/`` 
    205      
     207    
     208.. _celery: 
     209 
    206210Configure Celery 
    207211================ 
     
    217221    * ``rabbitmqctl set_permissions -p openplm openplm ".*" ".*" ".*"`` 
    218222 
    219 Then you must modify the `BROKER_*` settings, if you follow this tutorial, you 
     223Then you must modify the `BROKER_*` settings in the :file:`settings.py`, if you follow this tutorial, you 
    220224only have to change `BROKER_PASSWORD`. 
    221225 
     
    310314in the `from` field of each e-mail. Usually, this is a `no-reply@` address. 
    311315 
    312  
     316Troubleshootings 
     317================== 
     318 
     319.. contents:: 
     320    :local: 
     321 
     322Admin pages are ugly 
     323--------------------- 
     324 
     325openPLM ships with a simlink (:file:`/path/to/openPLM/media/admin`) that may 
     326be broken on your system. 
     327 
     328To fix this link, run the following command: 
     329``ln -s `python -c 'import django; print django.__path__[0]'`/contrib/admin/media 
     330/var/django/openPLM/trunk/openPLM/media/admin`` 
     331 
     332 
     333IOError at /object/create -- Socket closed 
     334------------------------------------------ 
     335 
     336This error is thrown if Celery is misconfigured and can not connect to 
     337RabbitMQ. See :ref:`celery` for more details, do not forget to edit 
     338the `BROKER_*` variables in the :file:`settings.py` file. 
     339 
     340I cannot find any objects 
     341---------------------------- 
     342 
     343You can rebuild the search index (:ref:`search-engine`) and see if openPLM 
     344finds your parts. 
     345 
     346It is possible that celery can not update the 
     347search index. You can check celery's log (:file:`/var/log/celery/*.log`) and 
     348see if it contains lines like ``[.. INFO/MainProcess] Got task from broker: openPLM.plmapp.tasks.update_index[...]``. It may be a permission problem and 
     349``chown www-data:www-data -R /var/openPLM/xapian_index/`` may fix it. 
     350 
     351I try to connect to http://server/ but I always get an "It works" page 
     352---------------------------------------------------------------------- 
     353 
     354Maybe your apache installation is a little broken. Does http://server/home/ 
     355show a more acceptable result? 
     356 
     357 
     358 
     359 
     360 
  • branches/3D/docs/devel/cookbook.rst

    r595 r674  
    4242=============== 
    4343 
     44Creation of a controller 
     45------------------------ 
     46 
     47.. code-block:: python 
     48 
     49   ctrl = PartController.create("Part_00011", "Part", "a", user, {"group":group}) 
    4450 
    4551.. _cookbook-tests: 
  • branches/3D/docs/devel/index.rst

    r613 r674  
    2525    modules 
    2626    applications 
    27  
     27    bom 
  • branches/3D/openPLM/computer/models.py

    r261 r674  
    2828from django.utils.translation import ugettext_noop 
    2929 
    30 from openPLM.plmapp.models import Part 
     30from openPLM.plmapp.models import Part, ParentChildLinkExtension, register_PCLE 
    3131from openPLM.plmapp.controllers import PartController 
    3232 
     
    6767register(MotherBoard) 
    6868 
     69class ReferenceDesignator(ParentChildLinkExtension): 
     70 
     71    reference_designator = models.CharField(max_length=200, blank=True) 
     72 
     73    def __unicode__(self): 
     74        return u"ReferenceDesignator<%s>" % self.reference_designator 
     75 
     76    @classmethod 
     77    def get_visible_fields(cls): 
     78        return ("reference_designator", ) 
     79 
     80    @classmethod 
     81    def apply_to(cls, parent): 
     82        return isinstance(parent, MotherBoard) 
     83    
     84    def clone(self, link, save, **data): 
     85        ref = data.get("reference_designator", self.reference_designator) 
     86        clone = ReferenceDesignator(link=link, reference_designator=ref) 
     87        if save: 
     88            clone.save() 
     89        return clone 
     90 
     91register(ReferenceDesignator) 
     92register_PCLE(ReferenceDesignator) 
     93 
    6994 
    7095class RAM(SinglePart): 
  • branches/3D/openPLM/media/css/openplm.css

    r662 r674  
    726726} 
    727727 
     728div.selector.tiny { 
     729    max-width: 6em; 
     730} 
  • branches/3D/openPLM/media/js/combobox.js

    r488 r674  
    33 
    44        $("select").uniform(); 
    5         $("div.selector").addClass("ui-widget ui-button ui-state-default ui-corner-all") 
     5        $("div.selector").addClass("ui-widget ui-button ui-state-default ui-corner-all"); 
     6        $("select.tiny").parent().addClass("tiny"); 
    67    } 
    78 
  • branches/3D/openPLM/plmapp/controllers/part.py

    r662 r674  
    8888        return can_add 
    8989 
    90     def add_child(self, child, quantity, order, unit=DEFAULT_UNIT): 
     90    def add_child(self, child, quantity, order, unit=DEFAULT_UNIT, **extension_data): 
    9191        """ 
    9292        Adds *child* to *self*. 
     
    123123        link.unit = unit 
    124124        link.save() 
     125        # handle plces 
     126        for PCLE in models.get_PCLEs(self.object): 
     127            name = PCLE._meta.module_name 
     128            if name in extension_data and PCLE.one_per_link(): 
     129                ext = PCLE(link=link, **extension_data[name]) 
     130                ext.save() 
    125131        # records creation in history 
    126132        self._save_histo(link.ACTION_NAME, 
     
    149155        self._save_histo("Delete - %s" % link.ACTION_NAME, "child : %s" % child) 
    150156 
    151     def modify_child(self, child, new_quantity, new_order, new_unit): 
     157    def modify_child(self, child, new_quantity, new_order, new_unit, 
     158            **extension_data): 
    152159        """ 
    153160        Modifies information about *child*. 
     
    173180        link = models.ParentChildLink.objects.get(parent=self.object, 
    174181                                                  child=child, end_time=None) 
     182        original_extension_data = link.get_extension_data() 
     183 
    175184        if (link.quantity == new_quantity and link.order == new_order and 
    176             link.unit == new_unit): 
     185            link.unit == new_unit and original_extension_data == extension_data): 
    177186            # do not make an update if it is useless 
    178187            return 
     
    180189        link.save() 
    181190        # make a new link 
    182         link2 = models.ParentChildLink(parent=self.object, child=child, 
    183                                        quantity=new_quantity, order=new_order, 
    184                                        unit=new_unit) 
     191        link2, extensions = link.clone(quantity=new_quantity, order=new_order, 
     192                       unit=new_unit, end_time=None, extension_data=extension_data) 
    185193        details = "" 
    186194        if link.quantity != new_quantity: 
     
    190198        if link.unit != new_unit: 
    191199            details += "unit changes from %s to %s" % (link.unit, new_unit) 
     200 
     201        # TODO: details of extension changes 
     202 
    192203        self._save_histo("Modify - %s" % link.ACTION_NAME, details) 
    193204        link2.save(force_insert=True) 
     205        # save cloned extensions 
     206        for ext in extensions: 
     207            ext.link = link2 
     208            ext.save(force_insert=True) 
     209        # add new extensions 
     210        for PCLE in models.get_PCLEs(self.object): 
     211            name = PCLE._meta.module_name 
     212            if (name in extension_data and name not in original_extension_data 
     213                and PCLE.one_per_link()): 
     214                ext = PCLE(link=link2, **extension_data[name]) 
     215                ext.save() 
    194216 
    195217    def get_children(self, max_level=1, current_level=1, date=None): 
     
    261283                    order = form.cleaned_data["order"] 
    262284                    unit = form.cleaned_data["unit"] 
    263                     self.modify_child(child, quantity, order, unit) 
     285                    self.modify_child(child, quantity, order, unit, 
     286                            **form.extensions) 
    264287 
    265288    def revise(self, new_revision): 
     
    267290        new_controller = super(PartController, self).revise(new_revision) 
    268291        for level, link in self.get_children(1): 
    269             new_controller.add_child(link.child, link.quantity, link.order, 
    270                     link.unit) 
     292            link.clone(save=True, parent=new_controller.object) 
    271293        return new_controller 
    272294 
  • branches/3D/openPLM/plmapp/forms.py

    r662 r674  
    2424 
    2525import re 
     26from collections import defaultdict 
    2627 
    2728from django import forms 
    2829from django.conf import settings 
    2930from django.forms.formsets import formset_factory, BaseFormSet 
    30 from django.forms.models import modelform_factory, modelformset_factory 
     31from django.forms.models import modelform_factory, modelformset_factory, \ 
     32        BaseModelFormSet 
    3133from django.contrib.auth.models import User, Group 
    3234from django.forms import ValidationError 
     
    196198    return None 
    197199 
     200def group_types(types): 
     201    res = [] 
     202    group = [] 
     203    for type_, long_name in types: 
     204        if long_name[0] not in '=>': 
     205            group = [] 
     206            res.append((long_name, group)) 
     207        group.append((type_, long_name)) 
     208    return res 
     209 
    198210class TypeForm(forms.Form): 
    199     LIST = m.get_all_users_and_plmobjects_with_level() 
     211    LIST = group_types(m.get_all_users_and_plmobjects_with_level()) 
    200212    type = forms.TypedChoiceField(choices=LIST) 
    201213 
    202214class TypeFormWithoutUser(forms.Form): 
    203     LIST_WO_USER = m.get_all_plmobjects_with_level() 
     215    LIST_WO_USER = group_types(m.get_all_plmobjects_with_level()) 
    204216    type = forms.TypedChoiceField(choices=LIST_WO_USER, 
    205217            label=_("Select a type")) 
     
    315327    unit = forms.ChoiceField(choices=UNITS, initial=DEFAULT_UNIT) 
    316328 
     329    def __init__(self, parent, *args, **kwargs): 
     330        super(AddChildForm, self).__init__(*args, **kwargs) 
     331        self._PCLEs = defaultdict(list) 
     332        for PCLE in m.get_PCLEs(parent): 
     333            for field in PCLE.get_editable_fields(): 
     334                model_field = PCLE._meta.get_field(field) 
     335                form_field = model_field.formfield() 
     336                field_name = "%s_%s" % (PCLE._meta.module_name, field) 
     337                self.fields[field_name] = form_field 
     338                self._PCLEs[PCLE].append(field) 
     339         
     340    def clean(self): 
     341        super(AddChildForm, self).clean() 
     342        self.extensions = {} 
     343        for PCLE, fields in self._PCLEs.iteritems(): 
     344            data = {} 
     345            for field in fields: 
     346                field_name = "%s_%s" % (PCLE._meta.module_name, field) 
     347                data[field] = self.cleaned_data[field_name] 
     348            self.extensions[PCLE._meta.module_name] = data 
     349        return self.cleaned_data 
    317350 
    318351class DisplayChildrenForm(forms.Form): 
     
    331364    quantity = forms.FloatField(widget=forms.TextInput(attrs={'size':'4'})) 
    332365    order = forms.IntegerField(widget=forms.TextInput(attrs={'size':'2'})) 
     366    unit = forms.ChoiceField(choices=UNITS, initial=DEFAULT_UNIT, 
     367            widget=forms.Select(attrs={"class":"tiny"})) 
     368 
    333369    class Meta: 
    334370        model = m.ParentChildLink 
    335371        fields = ["order", "quantity", "unit", "child", "parent",] 
     372     
     373    def clean(self): 
     374        super(ModifyChildForm, self).clean() 
     375        self.extensions = {} 
     376        for PCLE, fields in self.PCLEs.iteritems(): 
     377            data = {} 
     378            for field in fields: 
     379                field_name = "%s_%s" % (PCLE._meta.module_name, field) 
     380                data[field] = self.cleaned_data[field_name] 
     381            self.extensions[PCLE._meta.module_name] = data 
     382        return self.cleaned_data 
     383 
     384class BaseChildrenFormSet(BaseModelFormSet): 
     385    def add_fields(self, form, index): 
     386        super(BaseChildrenFormSet, self).add_fields(form, index) 
     387        form.PCLEs = defaultdict(list) 
     388        parent = form.instance.parent.get_leaf_object() 
     389        for PCLE in m.get_PCLEs(parent): 
     390            try: 
     391                ext = PCLE.objects.get(link=form.instance) 
     392            except PCLE.DoesNotExist: 
     393                ext = None 
     394            for field in PCLE.get_editable_fields(): 
     395                initial = getattr(ext, field, None) 
     396                model_field = PCLE._meta.get_field(field) 
     397                form_field = model_field.formfield(initial=initial) 
     398                field_name = "%s_%s" % (PCLE._meta.module_name, field) 
     399                if isinstance(form_field.widget, forms.TextInput): 
     400                    form_field.widget.attrs["size"] = 10 
     401                form.fields[field_name] = form_field 
     402                form.PCLEs[PCLE].append(field) 
    336403 
    337404ChildrenFormset = modelformset_factory(m.ParentChildLink, 
    338                                        form=ModifyChildForm, extra=0) 
     405       form=ModifyChildForm, extra=0, formset=BaseChildrenFormSet) 
    339406def get_children_formset(controller, data=None): 
    340407    if data is None: 
  • branches/3D/openPLM/plmapp/models.py

    r662 r674  
    8484import kjbuckets 
    8585from django.db import models 
     86from django.db.models.query import QuerySet 
    8687from django.db.models.signals import post_save 
    8788from django.conf import settings 
     
    619620    def get_attributes_and_values(self): 
    620621        return [(attr, getattr(self, attr)) for attr in self.attributes] 
     622 
     623    def get_leaf_object(self): 
     624        return get_all_plmobjects()[self.type].objects.get(id=self.id) 
    621625 
    622626# parts stuff 
     
    994998             
    995999            amount of child (a positive float) 
     1000        .. attribute:: unit 
     1001             
     1002            unit of the quantity 
    9961003        .. attribute:: order 
    9971004             
     
    10001007             
    10011008            date of end of the link, None if the link is still alive 
     1009 
    10021010    """ 
    10031011 
     
    10161024 
    10171025    def __unicode__(self): 
    1018         return u"ParentChildLink<%s, %s, %f, %d>" % (self.parent, self.child, 
    1019                                                      self.quantity, self.order) 
     1026        return u"ParentChildLink<%s, %s, %f, %s, %d>" % (self.parent, self.child, 
     1027                                 self.quantity, self.unit, self.order) 
     1028 
    10201029    def get_shortened_unit(self): 
     1030        """ Returns unit as a human readable string. 
     1031        If :attr:`unit` equals to "-", returns an empty string. 
     1032        """ 
    10211033        if self.unit == "-": 
    10221034            return u"" 
    10231035        return self.get_unit_display() 
    10241036 
     1037    @property 
     1038    def extensions(self): 
     1039        """ Returns a queryset of bound :class:`ParentChildLinkExtension`. """ 
     1040        return ParentChildLinkExtension.children.filter(link=self) 
     1041 
     1042    def get_extension_data(self): 
     1043        """ 
     1044        Returns a dictionary of extension data. The returned value can be passed 
     1045        as a valid arguement to :meth:`clone`. 
     1046        """ 
     1047 
     1048        extension_data = {} 
     1049        for ext in self.extensions: 
     1050            if ext.one_per_link(): 
     1051                extension_data[ext._meta.module_name] = ext.to_dict() 
     1052        return extension_data 
     1053 
     1054    def clone(self, save=False, extension_data=None, **kwargs): 
     1055        u""" 
     1056        Clone this link. 
     1057 
     1058        It is possible to pass additional arguement to override some original 
     1059        values. 
     1060 
     1061        :param save: If True, the cloned link and its extensions are saved 
     1062        :param extension_data: dictionary PCLE module name -> data of data 
     1063            that are given to :meth:`ParentChildLinkExtension.clone`. 
     1064         
     1065        :return: a tuple (cloned link, list of cloned extensions) 
     1066 
     1067        Example:: 
     1068 
     1069            >>> print link 
     1070            ParentChildLink<Part<PART_2/MotherBoard/a>, Part<ttd/RAM/a>, 4.000000, -, 10> 
     1071            >>> link.extensions 
     1072            [<ReferenceDesignator: ReferenceDesignator<m1,m2,>>] 
     1073            >>> clone, ext = link.clone(False, 
     1074            ...    {"referencedesignator" : { "reference_designator" : "new_value"}}, 
     1075            ...    quantity=51) 
     1076            >>> print clone 
     1077            ParentChildLink<Part<PART_2/MotherBoard/a>, Part<ttd/RAM/a>, 51.000000, -, 10> 
     1078            >>> print ext 
     1079            [<ReferenceDesignator: ReferenceDesignator<new_value>>] 
     1080             
     1081        """ 
     1082        # original data 
     1083        data = dict(parent=self.parent, child=self.child, 
     1084                quantity=self.quantity, order=self.order, unit=self.unit, 
     1085                end_time=self.end_time) 
     1086        # update data from kwargs 
     1087        for key, value in kwargs.iteritems(): 
     1088            if key in data: 
     1089                data[key] = value 
     1090        link = ParentChildLink(**data) 
     1091        if save: 
     1092            link.save() 
     1093        # clone the extensions 
     1094        extensions = [] 
     1095        extension_data = extension_data or {} 
     1096        for ext in self.extensions: 
     1097            extensions.append(ext.clone(link, save,  
     1098                **extension_data.get(ext._meta.module_name, {}))) 
     1099        return link, extensions 
     1100 
     1101 
     1102class ChildQuerySet(QuerySet): 
     1103    def iterator(self): 
     1104        for obj in super(ChildQuerySet, self).iterator(): 
     1105            yield obj.get_child_object() 
     1106 
     1107 
     1108class ChildManager(models.Manager): 
     1109    def get_query_set(self): 
     1110        return ChildQuerySet(self.model) 
     1111 
     1112 
     1113class ParentModel(models.Model): 
     1114    _child_name = models.CharField(max_length=100, editable=False) 
     1115 
     1116    class Meta: 
     1117        abstract = True 
     1118 
     1119    def save(self, *args, **kwargs): 
     1120        self._child_name = self.get_child_name() 
     1121        super(ParentModel, self).save(*args, **kwargs) 
     1122 
     1123    def get_child_name(self): 
     1124        if type(self) is self.get_parent_model(): 
     1125            return self._child_name 
     1126        return self.get_parent_link().related_query_name() 
     1127 
     1128    def get_child_object(self): 
     1129        return getattr(self, self.get_child_name()) 
     1130 
     1131    def get_parent_link(self): 
     1132        return self._meta.parents[self.get_parent_model()] 
     1133 
     1134    def get_parent_model(self): 
     1135        raise NotImplementedError 
     1136 
     1137    def get_parent_object(self): 
     1138        return getattr(self, self.get_parent_link().name) 
     1139 
     1140registered_PCLEs = [] 
     1141class ParentChildLinkExtension(ParentModel): 
     1142    """ 
     1143    Extension of a :class:`ParentChildLink` used to store additional data. 
     1144 
     1145    This class is abstract, subclass must define the :meth:`clone` method, 
     1146    add at least one field (or it would be useless) and may override 
     1147    :meth:`get_visible_fields` or :meth:`get_editable_fields`. 
     1148 
     1149    .. seealso:: 
     1150     
     1151        :ref:`bom_extensions` explains how to subclass this class. 
     1152    """ 
     1153 
     1154    #! link bound to the PCLE 
     1155    link = models.ForeignKey(ParentChildLink, related_name="%(class)s_link") 
     1156 
     1157    objects = models.Manager() 
     1158    children = ChildManager() 
     1159 
     1160    @classmethod 
     1161    def get_visible_fields(cls): 
     1162        """ 
     1163        Returns the list of visible fieldnames. 
     1164         
     1165        By default, returns an empty list. 
     1166        """ 
     1167        return [] 
     1168 
     1169    @classmethod 
     1170    def get_editable_fields(cls): 
     1171        """ 
     1172        Returns the list of editable fields. 
     1173 
     1174        By default, returns :meth:`get_visible_fields`. 
     1175        """ 
     1176        return list(cls.get_visible_fields()) 
     1177 
     1178    @classmethod 
     1179    def one_per_link(cls): 
     1180        """ Returns True if only one extension should be created per link. 
     1181 
     1182        By default return True if :meth:`get_visible_fields` returns a 
     1183        non empty list.""" 
     1184        return bool(cls.get_visible_fields()) 
     1185     
     1186    @classmethod 
     1187    def apply_to(cls, parent): 
     1188        """ 
     1189        Returns True if this extension applies to *parent*. 
     1190 
     1191        :param parent: part which will have a new child 
     1192        :type parent: :class:`Part` (its most specific subclass). 
     1193         
     1194        Returns True by default. 
     1195        """ 
     1196        return True 
     1197 
     1198    def clone(self, link, save=False, **data): 
     1199        """ 
     1200        Clone this extension. 
     1201         
     1202        **Subclass must define its implementation.** and respect the 
     1203        following specification: 
     1204 
     1205        :param link: the new cloned link, the cloned extension must be 
     1206                     bound to it 
     1207        :type link: :class:`ParentChildLink` 
     1208        :param save: True if the cloned extension must be saved, False 
     1209                     (the default) if it must not be saved. 
     1210        :type save: boolean 
     1211        :param data: additional data that override the original values 
     1212         
     1213        :return: the cloned extension 
     1214        """ 
     1215        raise NotImplementedError 
     1216 
     1217    def get_parent_model(self): 
     1218        return ParentChildLinkExtension 
     1219 
     1220    def to_dict(self): 
     1221        """ 
     1222        Returns a dictionary fieldnames -> value that can be safely passed as 
     1223        a kwargument to :meth:`clone` and that is used to compare two 
     1224        extensions.  
     1225        """ 
     1226        d = {} 
     1227        for field in self._meta.get_all_field_names(): 
     1228            if field not in ("id", "link", "_child_name", 
     1229                    'parentchildlinkextension_ptr'): 
     1230                d[field] = getattr(self, field) 
     1231        return d 
     1232     
     1233def register_PCLE(PCLE): 
     1234    """ 
     1235    Register *PCLE* so that openPLM can show its visible fields. 
     1236 
     1237    :param PCLE: the registered PCLE 
     1238    :type PCLE: a subclass of :class:`ParentChildLinkExtension`. 
     1239    """ 
     1240    registered_PCLEs.append(PCLE) 
     1241 
     1242def get_PCLEs(parent): 
     1243    """ 
     1244    Returns the list of registered :class:`ParentChildLinkExtension` that 
     1245    applied to *parent*. 
     1246    """ 
     1247    return [PCLE for PCLE in registered_PCLEs if PCLE.apply_to(parent)] 
     1248 
     1249 
    10251250class DocumentPartLink(Link): 
    10261251    """ 
     
    10461271    def __unicode__(self): 
    10471272        return u"DocumentPartLink<%s, %s>" % (self.document, self.part) 
    1048  
    10491273 
    10501274# abstraction stuff 
     
    11811405            default=lambda:str(random.getrandbits(512))) 
    11821406     
    1183      
     1407    
    11841408# import_models should be the last function 
    11851409 
  • branches/3D/openPLM/plmapp/templatetags/plmapp_tags.py

    r486 r674  
    5252    return " ".join(classes) 
    5353 
     54def key(d, key_name): 
     55    try: 
     56        value = d[key_name] 
     57    except KeyError: 
     58        from django.conf import settings 
     59        value = settings.TEMPLATE_STRING_IF_INVALID 
     60    return value 
     61key = register.filter('key', key) 
     62 
     63def attr(o, attr_name): 
     64    from django.conf import settings 
     65    return getattr(o, attr_name, settings.TEMPLATE_STRING_IF_INVALID) 
     66attr = register.filter('attr', attr) 
     67 
  • branches/3D/openPLM/plmapp/tests/__init__.py

    r662 r674  
    3939from openPLM.plmapp.tests.csvimport import * 
    4040from openPLM.plmapp.tests.archive import * 
     41from openPLM.plmapp.tests.pcle import * 
    4142 
    4243import openPLM.plmapp.models 
  • branches/3D/openPLM/plmapp/tests/archive.py

    r668 r674  
    1010    def setUp(self): 
    1111        super(ArchiveViewTestCase, self).setUp() 
    12         self.document = Document3DController.create('doc1', 'Document', 
     12        self.document = DocumentController.create('doc1', 'Document', 
    1313                'a', self.user, self.DATA) 
    1414        self.filenames = [] 
  • branches/3D/openPLM/plmapp/tests/controllers/document.py

    r472 r674  
    4848        self.controller = self.CONTROLLER.create("adoc", self.TYPE, "a", 
    4949                                                 self.user, self.DATA) 
    50         self.part = PartController.create("mpart", "Part", "a", self.user, 
    51                 self.DATA) 
    5250        self.old_files = [] 
     51 
     52    def get_part(self): 
     53        return PartController.create("mpart", "Part", "a", self.user, self.DATA) 
    5354 
    5455    def tearDown(self): 
     
    189190 
    190191    def test_attach_to_part(self): 
    191         self.controller.attach_to_part(self.part) 
     192        part = self.get_part() 
     193        self.controller.attach_to_part(part) 
     194        attached = self.controller.get_attached_parts()[0].part 
     195        self.assertEqual(part.id, attached.id) 
    192196     
    193197    def test_attach_to_part_error1(self): 
     
    208212     
    209213    def test_detach_part(self): 
    210         self.controller.attach_to_part(self.part) 
    211         self.controller.detach_part(self.part) 
    212         self.assertEqual(len(self.controller.get_attached_parts()), 0) 
     214        part = self.get_part() 
     215        self.controller.attach_to_part(part) 
     216        self.controller.detach_part(part) 
     217        self.assertEqual(self.controller.get_attached_parts().count(), 0) 
    213218 
    214219    def test_get_attached_parts(self): 
    215         self.controller.attach_to_part(self.part) 
     220        part = self.get_part() 
     221        self.controller.attach_to_part(part) 
    216222        links = list(self.controller.get_attached_parts()) 
    217         self.assertEqual([l.part for l in links], [self.part.object]) 
     223        self.assertEqual([l.part for l in links], [part.object]) 
    218224         
    219225    def test_get_attached_parts_empty(self): 
     
    222228 
    223229    def test_revise2(self): 
    224         self.controller.attach_to_part(self.part) 
     230        part = self.get_part() 
     231        self.controller.attach_to_part(part) 
    225232        self.controller.add_file(self.get_file()) 
    226233        f1 = self.controller.files.all()[0] 
     
    268275     
    269276    def test_checkin_errors3(self): 
     277        """ Tests that only the user who locked a file can check-in it.""" 
    270278        user = User(username="baduser") 
    271279        user.set_password("password") 
  • branches/3D/openPLM/plmapp/tests/controllers/part.py

    r662 r674  
    5050        self.controller3 = self.CONTROLLER.create("aPart3", self.TYPE, "a", 
    5151                                                  self.user, self.DATA) 
    52         self.controller4 = self.CONTROLLER.create("aPart4", self.TYPE, "a", 
    53                                                   self.user, self.DATA) 
    5452        self.document = DocumentController.create("Doc1", "Document", "a", 
    5553                self.user, self.DATA) 
    5654        self.document.add_file(self.get_file()) 
    57         self.document.promote() 
     55        self.document.state = self.document.lifecycle.official_state 
     56        self.document.object.save() 
    5857        for ctrl in (self.controller, self.controller2): 
    5958            ctrl.attach_to_document(self.document) 
     
    126125 
    127126    def test_get_children(self): 
     127        controller4 = self.CONTROLLER.create("aPart4", self.TYPE, "a", 
     128                                                  self.user, self.DATA) 
    128129        self.controller.add_child(self.controller2, 10, 15) 
    129130        date = datetime.datetime.now() 
    130131        self.controller2.add_child(self.controller3, 10, 15) 
    131         self.controller.add_child(self.controller4, 10, 15) 
     132        self.controller.add_child(controller4, 10, 15) 
    132133        wanted = [(1, self.controller2.object.pk), 
    133134                  (2, self.controller3.object.pk), 
    134                   (1, self.controller4.object.pk)] 
     135                  (1, controller4.object.pk)] 
    135136        children = [(lvl, lk.child.pk) for lvl, lk in self.controller.get_children(-1)] 
    136137        self.assertEqual(children, wanted) 
    137138        wanted = [(1, self.controller2.object.pk), 
    138                   (1, self.controller4.object.pk)] 
     139                  (1, controller4.object.pk)] 
    139140        # first level 
    140141        children = [(lvl, lk.child.pk) for lvl, lk in self.controller.get_children(1)] 
     
    146147 
    147148    def test_get_parents(self): 
     149        controller4 = self.CONTROLLER.create("aPart4", self.TYPE, "a", 
     150                                                  self.user, self.DATA) 
    148151        self.controller.add_child(self.controller2, 10, 15) 
    149152        date = datetime.datetime.now() 
    150153        self.controller2.add_child(self.controller3, 10, 15) 
    151         self.controller.add_child(self.controller4, 10, 15) 
     154        self.controller.add_child(controller4, 10, 15) 
    152155        wanted = [(1, self.controller2.object.pk), 
    153156                  (2, self.controller.object.pk),] 
  • branches/3D/openPLM/plmapp/tests/views.py

    r662 r674  
    365365        self.assertEquals(45, link.order) 
    366366        self.assertEquals(45.0, link.quantity) 
     367        self.assertEquals('cm', link.unit) 
    367368 
    368369    def test_parents_empty(self): 
  • branches/3D/openPLM/plmapp/views/ajax.py

    r662 r674  
    133133    data = {} 
    134134    if request.GET: 
    135         form = forms.AddChildForm(initial=request.GET) 
     135        form = forms.AddChildForm(part.object, initial=request.GET) 
    136136    else: 
    137         form = forms.AddChildForm(request.POST) 
     137        form = forms.AddChildForm(part.object, request.POST) 
    138138        if form.is_valid(): 
    139139            child = get_obj_from_form(form, request.user) 
    140140            part.add_child(child, form.cleaned_data["quantity"],  
    141141                           form.cleaned_data["order"], 
    142                            form.cleaned_data["unit"]) 
     142                           form.cleaned_data["unit"], 
     143                           **form.extensions) 
    143144            return {"result" : "ok"} 
    144145        else: 
  • branches/3D/openPLM/plmapp/views/main.py

    r662 r674  
    5353from operator import attrgetter 
    5454from mimetypes import guess_type 
     55from collections import defaultdict 
    5556 
    5657from django.shortcuts import render_to_response 
     
    232233        maximum = max(children, key=attrgetter("level")).level 
    233234        children = (c for c in children if c.level == maximum) 
    234     # convert level to html space 
    235     #children = (("&nbsp;" * 2 * (level-1), link) for level, link in children) 
    236  
     235    children = list(children) 
     236    extra_columns = [] 
     237    extension_data = defaultdict(dict) 
     238    for PCLE in models.get_PCLEs(obj.object): 
     239        fields = PCLE.get_visible_fields() 
     240        if fields: 
     241            extra_columns.extend((f, PCLE._meta.get_field(f).verbose_name)  
     242                    for f in fields) 
     243            for child in children: 
     244                link = child.link 
     245                for field in fields: 
     246                    try: 
     247                        e = PCLE.objects.get(link=link) 
     248                        extension_data[link][field] = getattr(e, field) 
     249                    except PCLE.DoesNotExist: 
     250                        extension_data[link][field] = "" 
    237251    ctx.update({'current_page':'BOM-child', 
    238252                'children': children, 
     253                'extra_columns' : extra_columns, 
     254                'extension_data': extension_data, 
    239255                "display_form" : display_form}) 
    240256    return r2r('DisplayObjectChild.htm', ctx, request) 
     
    263279    else: 
    264280        formset = get_children_formset(obj) 
     281    extra_columns = [] 
     282    extra_fields = [] 
     283    for PCLE in models.get_PCLEs(obj.object): 
     284        fields = PCLE.get_visible_fields() 
     285        if fields: 
     286            extra_columns.extend((f, PCLE._meta.get_field(f).verbose_name)  
     287                    for f in fields) 
     288            prefix = PCLE._meta.module_name 
     289            extra_fields.extend('%s_%s' % (prefix, f) for f in fields) 
    265290    ctx.update({'current_page':'BOM-child', 
     291                'extra_columns' : extra_columns, 
     292                'extra_fields' : extra_fields, 
    266293                'children_formset': formset, }) 
    267294    return r2r('DisplayObjectChildEdit.htm', ctx, request) 
     
    279306     
    280307    if request.POST: 
    281         add_child_form = AddChildForm(request.POST) 
     308        add_child_form = AddChildForm(obj.object, request.POST) 
    282309        if add_child_form.is_valid(): 
    283310            child_obj = get_obj_from_form(add_child_form, request.user) 
     
    285312                          add_child_form.cleaned_data["quantity"], 
    286313                          add_child_form.cleaned_data["order"], 
    287                           add_child_form.cleaned_data["unit"]) 
     314                          add_child_form.cleaned_data["unit"], 
     315                          **add_child_form.extensions) 
    288316            return HttpResponseRedirect(obj.plmobject_url + "BOM-child/")  
    289317    else: 
    290         add_child_form = AddChildForm() 
     318        add_child_form = AddChildForm(obj.object) 
    291319        ctx['current_page'] = 'BOM-child' 
    292320    ctx.update({'link_creation': True, 
  • branches/3D/openPLM/settings_tests.py

    r662 r674  
    105105    'openPLM.cae', 
    106106    'openPLM.office', 
     107    'openPLM.plmapp.tests', 
    107108    'openPLM.document3D', 
    108109) 
  • branches/3D/openPLM/templates/DisplayObjectChild.htm

    r662 r674  
    3737            <th class="Content"> {{ obj.type }} </th> 
    3838            <th class="Content"> {{ obj.name }} </th> 
     39            {% for field, verbose_name in extra_columns %} 
     40                <th class="Content"> {{ verbose_name|capfirst }} </th> 
     41            {% endfor %} 
    3942            <th class="Content"> {{ obj.state.name }} </th> 
    4043        </tr> 
     
    5659                <td class="Content"> {{ link.child.type }} </td> 
    5760                <td class="Content"> {{ link.child.name }} </td> 
     61                {% for field, verbose_name in extra_columns %} 
     62                    <td class="Content"> {{ extension_data|key:link|key:field }} </td> 
     63                {% endfor %} 
    5864                <td class="Content"> {{ link.child.state.name }} </td> 
    5965            </tr> 
    6066        {% endfor %} 
    61         </table> 
     67    </table> 
    6268{% endblock %} 
    6369 
  • branches/3D/openPLM/templates/DisplayObjectChildEdit.htm

    r662 r674  
    1616            <th class="Content"> {{ obj.type }} </th> 
    1717            <th class="Content"> {{ obj.name }} </th> 
     18            {% for field, verbose_name in extra_columns %} 
     19                <th class="Content"> {{ verbose_name|capfirst }} </th> 
     20            {% endfor %} 
    1821            <th class="Content"> {{ obj.state.name }} </th> 
    1922            <th class="Content"> {% trans "Delete ?" %} </th> 
     
    3538                <td class="Content"> {{ form.instance.child.type }} </td> 
    3639                <td class="Content"> {{ form.instance.child.name }} </td> 
     40                {% for field in extra_fields %} 
     41                    <td class="Content"> {{ form|key:field }} </td> 
     42                {% endfor %} 
    3743                <td class="Content"> {{ form.instance.child.state.name }} </td> 
    3844                <td class="Content"> {{ form.delete }} </td> 
Note: See TracChangeset for help on using the changeset viewer.