def _get_parts_and_children(self, cr, uid, classification, order = lambda x: x.participant.name, datetime_from=_MIN_DATETIME, datetime_to=_MAX_DATETIME, context=None ):
     participations={}
     child_groups=set()
     part_ids = None
     for groups_rel in classification.groups_rel_ids:
         part_ids2 = set()
         group_domain=groups_rel.direction=='up' and groups_rel.child_id or groups_rel.parent_id
         group_child=groups_rel.direction=='down' and groups_rel.child_id or groups_rel.parent_id
         child_groups.add((group_child.id,group_child.name))
         for ga in group_domain.assignation_ids:
             key=(ga.participation_id.id,order(ga.participation_id))
             part_ids2.add(key)
             if key not in participations:
                 participations[key]= groups_rel.direction == 'down' and [(datetime_from,datetime_to)] or []
             unitats_a_afegir = [(max(datetime_from,ga.datetime_from),min(datetime_to,ga.datetime_to))]
             if groups_rel.direction == 'down':
                 participations[key] = _complementa_llista(participations[key])
                 unitats_a_afegir = _complementa_llista(unitats_a_afegir)
             for interval in unitats_a_afegir:
                 participations[key] = _inclou_interval_en_llista(participations[key], interval)
             if groups_rel.direction == 'down':
                 participations[key] = _complementa_llista(participations[key])
         if part_ids is None:
             part_ids = set(part_ids2)
         else:
             if groups_rel.direction=='down':
                 part_ids.intersection_update(part_ids2)
             else:
                 part_ids.update(part_ids2)
     participations = dict( (key,value) for (key,value) in participations.items() if key in part_ids)
     return participations, child_groups
    def remove_assignation(self, cr, uid, participation_id, group, classifying = False, datetime_from=_MIN_DATETIME, datetime_to=_MAX_DATETIME, context=None):
        if not context:
            context={}
        time_intro = diff_time(context = context)
        datetime_from=max(_MIN_DATETIME,datetime_from or _MIN_DATETIME)
        datetime_to=min(_MAX_DATETIME,datetime_to or _MAX_DATETIME)
        
        if type(group) in (int,long):
            group=self.pool.get('groups.group').browse(cr, uid, group, context={'withoutBlank': False,})
        if not _CHANGE_ASSIGNATION_GROUP_IDS_KEY in context:
            context[_CHANGE_ASSIGNATION_GROUP_IDS_KEY]=[]
        if group.id in context[_CHANGE_ASSIGNATION_GROUP_IDS_KEY]:
            diff_time(title = 'Remove from group', group_name = group.name, participation_id = participation_id, datetime_from = datetime_from, datetime_to = datetime_to, classifying = classifying, time_ant = time_intro, context = context)
            return
        context[_CHANGE_ASSIGNATION_GROUP_IDS_KEY].append(group.id)
        
        ga_ids=self.search(cr, uid, [('group_id','=',group.id),('participation_id','=',participation_id),('datetime_from','<',datetime_to),('datetime_to','>',datetime_from)])

        datetime_from_min=datetime_from
        datetime_to_max=datetime_to
        ints = []
        for data in self.read(cr, uid, ga_ids, ['datetime_from','datetime_to'], context={'withoutBlank': False,}):
            # Treu l'assignacio a tots  els grups inferiors
            for child_rel in group.children_ids:
                if child_rel.direction=='down':
                    self.remove_assignation(cr, uid, participation_id, child_rel.child_id,
                                            datetime_from=max(datetime_from,data['datetime_from']),
                                            datetime_to=min(datetime_to,data['datetime_to']) , context=context)
                else:
                    children_ids = self.search(cr, uid, [('participation_id','=',participation_id),
                                          ('group_id','=',child_rel.child_id.id),
                                          ('datetime_from','<',min(datetime_to,data['datetime_to'])),
                                          ('datetime_to','>',max(datetime_from,data['datetime_from'])), ])
                    if children_ids:
                        raise orm.except_orm('Problem',"Domini del fill amb ids %s massa gran." % (children_ids,))

            ints.append( (max(datetime_from,data['datetime_from']), min(datetime_to,data['datetime_to'])) )
            datetime_from_min=min(data['datetime_from'],datetime_from_min)
            datetime_to_max=max(data['datetime_to'],datetime_to_max)
        if datetime_from_min<datetime_from:
            super(groups_group_assignation, self).create(cr, uid, {'participation_id': participation_id, 'group_id': group.id, 'datetime_from': datetime_from_min, 'datetime_to': datetime_from,})
        if datetime_to_max>datetime_to:
            super(groups_group_assignation, self).create(cr, uid, {'participation_id': participation_id, 'group_id': group.id, 'datetime_from': datetime_to, 'datetime_to': datetime_to_max,})
        super(groups_group_assignation, self).unlink(cr, uid, ga_ids)
        
        # Treiem l'assignacio de tots els pares del qual aquest es un grup de la classificacio
        for parent_rel in group.parent_ids:
            if parent_rel.classification and not classifying and parent_rel.direction=='up':
                for (dtf,dtt) in ints:
                    llista = []
                    for data in self.read(cr, uid, self.search(cr, uid, [
                        ('participation_id','=',participation_id),
                        ('group_id.parent_ids','in',[brother.id for brother in parent_rel.classification.groups_rel_ids if brother.id != parent_rel.id]),
                        ]), ['datetime_from','datetime_to'], context={'withoutBlank': False,}):
                        llista = _inclou_interval_en_llista(llista, (data['datetime_from'],data['datetime_to']))
                    for (dtf1, dtt1) in _complementa_llista(llista, (dtf,dtt)):
                        self.remove_assignation(cr, uid, participation_id, parent_rel.parent_id, datetime_from=dtf1, datetime_to=dtt1, context=context)
        diff_time(title = 'Remove from group', group_name = group.name, participation_id = participation_id, datetime_from = datetime_from, datetime_to = datetime_to, classifying = classifying, time_ant = time_intro, context = context)
 def _domain_by_participation(self, cr, uid, group_id, participation_id, datetime_from = _MIN_DATETIME, datetime_to = _MAX_DATETIME, context = None):
     obj = self.pool.get('groups.groups_rel')
     obj_ga = self.pool.get('groups.group_assignation')
     datetime_from = max(datetime_from, _MIN_DATETIME)
     datetime_to = min(datetime_to, _MAX_DATETIME) 
     llista = []
     for groups_rel in obj.browse(cr, uid, obj.search(cr, uid, [('child_id','=',group_id),('direction','=','down')])):
         for dicci in obj_ga.read(cr, uid, obj_ga.search(cr, uid, [('group_id','=',groups_rel.parent_id.id),('participation_id','=',participation_id)]), ['datetime_from','datetime_to'], context ={'withoutBlank': False}):
             for dtf,dtt in _complementa_llista([(dicci['datetime_from'],dicci['datetime_to'])]):
                 llista = _inclou_interval_en_llista(llista, (dtf,dtt))
     return [(max(dtf,datetime_from),min(dtt,datetime_to)) for dtf,dtt in _complementa_llista(llista) if dtt > datetime_from and dtf < datetime_to]
    def add_assignation(self, cr, uid, participation_id, group, classifying = False, datetime_from=_MIN_DATETIME, datetime_to=_MAX_DATETIME, context=None):
        if not context:
            context={}
        time_intro = diff_time(context = context)
        ret=None
        datetime_from=max(_MIN_DATETIME,datetime_from or _MIN_DATETIME)
        datetime_to=min(_MAX_DATETIME,datetime_to or _MAX_DATETIME)
        if type(group) in (int,long):
            group=self.pool.get('groups.group').browse(cr, uid, group, context={'withoutBlank': False })

        # Don't repeat group
        if not _CHANGE_ASSIGNATION_GROUP_IDS_KEY in context:
            context[_CHANGE_ASSIGNATION_GROUP_IDS_KEY]=[]
        if group.id in context[_CHANGE_ASSIGNATION_GROUP_IDS_KEY]:
            diff_time(title='Add to group', group_name = group.name, participation_id = participation_id, datetime_from = datetime_from, datetime_to = datetime_to, classifying = classifying, time_ant = time_intro, context = context)
            return
        context[_CHANGE_ASSIGNATION_GROUP_IDS_KEY].append(group.id)

        # Els pares que baixen domini cap el grup resulten amb un domini interseccio
        unio_dels_dominis_complementaris=[]
        for parent_rel in group.parent_ids:
            if parent_rel.direction=='down':
                ga_ids=self.pool.get('groups.group_assignation').search(cr, uid, [('group_id','=',parent_rel.parent_id.id),('participation_id','=',participation_id),('datetime_from','>',datetime_to),('datetime_to','<',datetime_from)])
                for ga in self.browse(cr, uid, ga_ids, context={'withoutBlank': False,}):
                    if ga.datetime_from>datetime_from:
                        _inclou_interval_en_llista(unio_dels_dominis_complementaris,(datetime_from,ga.datetime_from))
                    if ga.datetime_from<datetime_from:
                        _inclou_interval_en_llista(unio_dels_dominis_complementaris,(ga.datetime_to,datetime_to))

        # De la interseccio potser surten mes d'un interval
        for (dt_from,dt_to) in _complementa_llista(unio_dels_dominis_complementaris,(datetime_from,datetime_to)):
            # Amplia assignacions dels grups superiors per la participacio
            # Si hi ha un pare sense classificacio ha de ser pare unic perque en cas contrari no sabem a quin pare hem d'ampliar l'assignacio

            # Fusiona assignacions dins de l'interval respectant els limits de les ja incloses
            ga_ids=self.search(cr, uid, [('group_id','=',group.id),('participation_id','=',participation_id),('datetime_from','<=',dt_to),('datetime_to','>=',dt_from)])
            ret = 'ga_id' in context and context['ga_id'] in ga_ids and context['ga_id'] or 0

            datetime_from_min=dt_from
            datetime_to_max=dt_to
            
            unio_dins = []
            for item in self.browse(cr, uid, ga_ids, context={'withoutBlank': False,}):
                datetime_from_min=min(item.datetime_from or _MIN_DATETIME,datetime_from_min)
                datetime_to_max=max(item.datetime_to or _MAX_DATETIME,datetime_to_max)
                _inclou_interval_en_llista(unio_dins, (max(item.datetime_from,datetime_from,_MIN_DATETIME),min(item.datetime_to,datetime_to,_MAX_DATETIME) ) )
            for (dt_from2,dt_to2) in _complementa_llista(unio_dins,(datetime_from,datetime_to)):
                for parent_rel in group.parent_ids:
                    if parent_rel.direction=='up':
                        self.add_assignation(cr, uid, participation_id, parent_rel.parent_id.id, datetime_from=dt_from2, datetime_to=dt_to2, context=context)
                    if parent_rel.classification:
                        for group_rel in parent_rel.classification.groups_rel_ids:
                            if group_rel.child_id.id!=group.id:
                                self.remove_assignation(cr, uid, participation_id, group_rel.child_id.id, classifying = True, datetime_from=dt_from2, datetime_to=dt_to2, context=context)
            vals={'participation_id': participation_id, 'group_id': group.id, 'datetime_from': datetime_from_min, 'datetime_to': datetime_to_max,}
            if ret:
                super(groups_group_assignation, self).write(cr, uid, [ret], vals)
                ga_ids.remove(ret)
            else:
                if 'ga_id' in context and context['ga_id']:
                    vals['id'] = context['ga_id']
                ret=super(groups_group_assignation, self).create(cr, uid, vals)
            super(groups_group_assignation, self).unlink(cr, uid, ga_ids)

            # Decidim a quin grup de les divisions afegim l'assignacio
            for classification in set(child_rel.classification for child_rel in group.children_ids if child_rel.direction=='down' and child_rel.classification):
                self.pool.get('groups.classification').add_assignation(cr, uid, participation_id, classification,datetime_from=dt_from, datetime_to=dt_to, context=context)
        diff_time(title = 'Add to group', group_name = group.name, participation_id = participation_id, datetime_from = datetime_from, datetime_to = datetime_to, classifying = classifying, time_ant = time_intro, context = context)
        return ret