コード例 #1
0
 def __init__(self, *args, **kwargs):
     super().__init__(*args, **kwargs)
     # TODO: add an 'exclude' argument in creme_entity_content_types() ??
     get_for_model = ContentType.objects.get_for_model
     is_invalid = gui_bricks.brick_registry.is_model_invalid
     self.fields['ctype'].ctypes = (
         get_for_model(model)
         for model in creme_registry.iter_entity_models()
         if not is_invalid(model))
コード例 #2
0
def filtered_entity_ctypes(app_labels):
    ext_app_labels = {
        app_config.label
        for app_config in extended_app_configs(app_labels)
    }
    get_ct = ContentType.objects.get_for_model

    for model in creme_registry.iter_entity_models():
        if model._meta.app_label in ext_app_labels:
            yield get_ct(model)
コード例 #3
0
def filtered_entity_ctypes(
    app_labels
):  # TODO: move to creme_core.utils ?? (improve iter_entity_models() ?)
    ext_app_labels = {
        app_config.label
        for app_config in extended_app_configs(app_labels)
    }
    get_ct = ContentType.objects.get_for_model

    for model in creme_registry.iter_entity_models():
        if model._meta.app_label in ext_app_labels:
            yield get_ct(model)
コード例 #4
0
    def detailview_display(self, context):
        # NB: we wrap the ContentType instances instead of store extra data in
        #     them because the instances are stored in a global cache, so we do
        #     not want to mutate them.
        class _ContentTypeWrapper:  # TODO: move from here ?
            __slots__ = ('ctype', 'locations_info', 'default_count')

            def __init__(self, ctype):
                self.ctype = ctype
                self.default_count = 0
                self.locations_info = (
                )  # List of tuples (role_arg, role_label, block_count)
                # with role_arg == role.id or 'superuser'

        # TODO: factorise with SearchConfigBlock ?
        # TODO: factorise with CustomBlockConfigItemCreateForm , add a method in block_registry ?
        get_ct = ContentType.objects.get_for_model
        is_invalid = self.brick_registry.is_model_invalid
        ctypes = [
            _ContentTypeWrapper(get_ct(model))
            for model in creme_registry.iter_entity_models()
            if not is_invalid(model)
        ]

        sort_key = collator.sort_key
        ctypes.sort(key=lambda ctw: sort_key(str(ctw.ctype)))

        btc = self.get_template_context(
            context,
            ctypes,
            max_conf_count=UserRole.objects.count() +
            1,  # NB: '+ 1' is for super-users config.
        )

        ctypes_wrappers = btc['page'].object_list

        brick_counts = defaultdict(
            lambda: defaultdict(int)
        )  # brick_counts[content_type.id][(role_id, superuser)] -> count
        role_ids = set()

        for bdl in BrickDetailviewLocation.objects \
                                          .filter(content_type__in=[ctw.ctype for ctw in ctypes_wrappers])\
                                          .exclude(zone=BrickDetailviewLocation.HAT):
            if bdl.brick_id:  # Do not count the 'place-holder' (empty block IDs which mean "no-block for this zone")
                role_id = bdl.role_id
                brick_counts[bdl.content_type_id][(role_id,
                                                   bdl.superuser)] += 1
                role_ids.add(role_id)

        role_names = dict(
            UserRole.objects.filter(id__in=role_ids).values_list('id', 'name'))
        superusers_label = gettext('Superuser')  # TODO: cached_lazy_gettext

        for ctw in ctypes_wrappers:
            count_per_role = brick_counts[ctw.ctype.id]
            ctw.default_count = count_per_role.pop((None, False), 0)

            ctw.locations_info = locations_info = []
            for (role_id, superuser), block_count in count_per_role.items():
                if superuser:
                    role_arg = 'superuser'
                    role_label = superusers_label
                else:
                    role_arg = role_id
                    role_label = role_names[role_id]

                locations_info.append((role_arg, role_label, block_count))

            locations_info.sort(
                key=lambda t: sort_key(t[1]))  # Sort by role label

        btc['default_count'] = BrickDetailviewLocation.objects.filter(
            content_type=None,
            role=None,
            superuser=False,
        ).count()

        return self._render(btc)
コード例 #5
0
def advanced_search(models_IDs, research_terms, props_IDs, user):
    total = 0
    results = []
    models = []

    # We will need to access to model class so we retrieve it with the id
    if not models_IDs:
        # Add all the existing models
        models.extend(creme_registry.iter_entity_models())
    else:
        # Add just the requested models
        for model_ID in models_IDs:
            models.append(get_ct_or_404(model_ID).model_class())

    if(len(models) > 1): # Useless to sort when we have only one model
        models.sort(key=lambda m: m._meta.verbose_name)
    
    filter_viewable = partial(EntityCredentials.filter, user=user)
    searcher = Searcher(models, user)
    
    for model in models:
        # To retrieve the entities the user is authorized to see
        entities = list(filter_viewable \
                            (queryset=searcher.search(model, research_terms)))

        # Here we will remove the entities which don't have the
        # requested properties
        if props_IDs:
            
            # We need to add [:] because some entity will be removed
            # Otherwise some entities will not be processed
            # http://stackoverflow.com/a/1352908
            for entity in entities[:]:
                # props is the list of the properties related to the
                # entity and not the properties the user is looking for
                props = list(CremeProperty.objects.filter \
                                 (creme_entity = entity.id))

                # If the entity have some properties
                if len(props) > 0:
                    count_properties_found = len(props)

                    # We decrement a number if a requested property is
                    # not found. TODO: Better explain the algorithm...
                    for prop in props:
                        if props_IDs.count(prop.type_id) == 0:
                            count_properties_found -= 1

                    if count_properties_found < len(props_IDs):
                        entities.remove(entity)

                else: # We remove it because we are looking for props
                    entities.remove(entity)

        total += len(entities)
        results.append({'model':    model,
                        'fields':   searcher.get_fields(model),
                        'entities': entities,
                        }
                       )

    models_list = [model._meta.verbose_name for model in models]

    return total, results, models_list
コード例 #6
0
def advanced_search(models_IDs, research_terms, props_IDs, user):
    total = 0
    results = []
    models = []

    # We will need to access to model class so we retrieve it with the id
    if not models_IDs:
        # Add all the existing models
        models.extend(creme_registry.iter_entity_models())
    else:
        # Add just the requested models
        for model_ID in models_IDs:
            models.append(get_ct_or_404(model_ID).model_class())

    if (len(models) > 1):  # Useless to sort when we have only one model
        models.sort(key=lambda m: m._meta.verbose_name)

    filter_viewable = partial(EntityCredentials.filter, user=user)
    searcher = Searcher(models, user)

    for model in models:
        # To retrieve the entities the user is authorized to see
        entities = list(filter_viewable \
                            (queryset=searcher.search(model, research_terms)))

        # Here we will remove the entities which don't have the
        # requested properties
        if props_IDs:

            # We need to add [:] because some entity will be removed
            # Otherwise some entities will not be processed
            # http://stackoverflow.com/a/1352908
            for entity in entities[:]:
                # props is the list of the properties related to the
                # entity and not the properties the user is looking for
                props = list(CremeProperty.objects.filter \
                                 (creme_entity = entity.id))

                # If the entity have some properties
                if len(props) > 0:
                    count_properties_found = len(props)

                    # We decrement a number if a requested property is
                    # not found. TODO: Better explain the algorithm...
                    for prop in props:
                        if props_IDs.count(prop.type_id) == 0:
                            count_properties_found -= 1

                    if count_properties_found < len(props_IDs):
                        entities.remove(entity)

                else:  # We remove it because we are looking for props
                    entities.remove(entity)

        total += len(entities)
        results.append({
            'model': model,
            'fields': searcher.get_fields(model),
            'entities': entities,
        })

    models_list = [model._meta.verbose_name for model in models]

    return total, results, models_list
コード例 #7
0
ファイル: bricks.py プロジェクト: mrjmad/creme_crm
    def detailview_display(self, context):
        # NB: we wrap the ContentType instances instead of store extra data in
        #     them because the instances are stored in a global cache, so we do
        #     not want to mutate them.
        class _ContentTypeWrapper:
            __slots__ = ('ctype', 'all_users_filters', 'owned_filters')

            def __init__(this, ctype):
                this.ctype = ctype
                this.all_users_filters = ()
                this.owned_filters = ()

        # TODO: factorise with SearchConfigBrick ?
        get_ct = ContentType.objects.get_for_model
        user = context['user']
        has_perm = user.has_perm_to_access
        ctypes = [
            _ContentTypeWrapper(get_ct(model))
            for model in creme_registry.iter_entity_models()
            if has_perm(model._meta.app_label)
        ]

        sort_key = collator.sort_key
        ctypes.sort(key=lambda ctw: sort_key(str(ctw.ctype)))

        btc = self.get_template_context(context, ctypes)

        ctypes_wrappers = btc['page'].object_list

        # NB: efilters[content_type.id][user.id] -> List[EntityFilter]
        efilters = defaultdict(lambda: defaultdict(list))
        user_ids = set()

        for efilter in EntityFilter.objects.filter(
                filter_type=EF_USER,
                entity_type__in=[ctw.ctype for ctw in ctypes_wrappers],
        ):
            # TODO: templatetags instead ?
            efilter.edition_perm = efilter.can_edit(user)[0]
            efilter.deletion_perm = efilter.can_delete(user)[0]

            user_id = efilter.user_id
            efilters[efilter.entity_type_id][user_id].append(efilter)
            user_ids.add(user_id)

        users = get_user_model().objects.in_bulk(user_ids)

        def efilter_key(efilter):
            return sort_key(efilter.name)

        for ctw in ctypes_wrappers:
            ctype_efilters_per_users = efilters[ctw.ctype.id]

            all_users_filters = ctype_efilters_per_users.pop(None, None) or []
            all_users_filters.sort(key=efilter_key)

            ctw.all_users_filters = all_users_filters

            ctw.owned_filters = [(
                str(users[user_id]),
                sorted(user_efilters, key=efilter_key),
            ) for user_id, user_efilters in ctype_efilters_per_users.items()]

        return self._render(btc)
コード例 #8
0
    def populate(self):
        already_populated = RelationType.objects.filter(
            pk=constants.REL_SUB_SOLD).exists()

        Act = commercial.get_act_model()
        ActObjectivePattern = commercial.get_pattern_model()
        Strategy = commercial.get_strategy_model()
        Contact = persons.get_contact_model()
        Organisation = persons.get_organisation_model()
        Product = products.get_product_model()
        Service = products.get_service_model()

        RelationType.create(
            (constants.REL_SUB_SOLD, _('has sold'), [Contact, Organisation]),
            (constants.REL_OBJ_SOLD, _('has been sold by'), [Product, Service
                                                             ]),
        )

        complete_goal_models = {*creme_registry.iter_entity_models()}
        complete_goal_models.discard(Strategy)
        if apps.is_installed('creme.billing'):
            from creme import billing
            from creme.billing.registry import lines_registry

            complete_goal_models.discard(billing.get_credit_note_model())
            complete_goal_models.discard(billing.get_template_base_model())
            complete_goal_models.difference_update(lines_registry)

        RelationType.create(
            (
                constants.REL_SUB_COMPLETE_GOAL,
                _('completes a goal of the commercial action'),
                complete_goal_models,
            ),
            (
                constants.REL_OBJ_COMPLETE_GOAL,
                _('is completed thanks to'),
                [Act],
            ),
        )

        # ---------------------------
        CremePropertyType.create(constants.PROP_IS_A_SALESMAN,
                                 _('is a salesman'), [Contact])

        # ---------------------------
        MarketSegment.objects.get_or_create(
            property_type=None,
            defaults={'name': _('All the organisations')},
        )

        # ---------------------------
        for i, title in enumerate(
            [_('Phone calls'), _('Show'),
             _('Demo')], start=1):
            create_if_needed(ActType, {'pk': i}, title=title, is_custom=False)

        # ---------------------------
        create_hf = HeaderFilter.objects.create_if_needed
        create_hf(
            pk=constants.DEFAULT_HFILTER_ACT,
            model=Act,
            name=_('Com Action view'),
            cells_desc=[
                (EntityCellRegularField, {
                    'name': 'name'
                }),
                (EntityCellRegularField, {
                    'name': 'expected_sales'
                }),
                (EntityCellRegularField, {
                    'name': 'due_date'
                }),
            ],
        )
        create_hf(
            pk=constants.DEFAULT_HFILTER_STRATEGY,
            model=Strategy,
            name=_('Strategy view'),
            cells_desc=[(EntityCellRegularField, {
                'name': 'name'
            })],
        )
        create_hf(
            pk=constants.DEFAULT_HFILTER_PATTERN,
            model=ActObjectivePattern,
            name=_('Objective pattern view'),
            cells_desc=[
                (EntityCellRegularField, {
                    'name': 'name'
                }),
                (EntityCellRegularField, {
                    'name': 'segment'
                }),
            ],
        )

        # ---------------------------
        def build_custom_form_items(creation_descriptor, edition_descriptor,
                                    field_names):
            base_groups_desc = [
                {
                    'name':
                    _('General information'),
                    'layout':
                    LAYOUT_DUAL_FIRST,
                    'cells': [
                        *((EntityCellRegularField, {
                            'name': fname
                        }) for fname in field_names),
                        (
                            EntityCellCustomFormSpecial,
                            {
                                'name':
                                EntityCellCustomFormSpecial.
                                REMAINING_REGULARFIELDS
                            },
                        ),
                    ],
                },
                {
                    'name': _('Description'),
                    'layout': LAYOUT_DUAL_SECOND,
                    'cells': [
                        (EntityCellRegularField, {
                            'name': 'description'
                        }),
                    ],
                },
                {
                    'name':
                    _('Custom fields'),
                    'layout':
                    LAYOUT_DUAL_SECOND,
                    'cells': [
                        (
                            EntityCellCustomFormSpecial,
                            {
                                'name':
                                EntityCellCustomFormSpecial.
                                REMAINING_CUSTOMFIELDS
                            },
                        ),
                    ],
                },
            ]

            CustomFormConfigItem.objects.create_if_needed(
                descriptor=creation_descriptor,
                groups_desc=[
                    *base_groups_desc,
                    {
                        'name':
                        _('Properties'),
                        'cells': [
                            (
                                EntityCellCustomFormSpecial,
                                {
                                    'name':
                                    EntityCellCustomFormSpecial.
                                    CREME_PROPERTIES
                                },
                            ),
                        ],
                    },
                    {
                        'name':
                        _('Relationships'),
                        'cells': [
                            (
                                EntityCellCustomFormSpecial,
                                {
                                    'name':
                                    EntityCellCustomFormSpecial.RELATIONS
                                },
                            ),
                        ],
                    },
                ],
            )
            CustomFormConfigItem.objects.create_if_needed(
                descriptor=edition_descriptor,
                groups_desc=base_groups_desc,
            )

        build_custom_form_items(
            creation_descriptor=custom_forms.ACT_CREATION_CFORM,
            edition_descriptor=custom_forms.ACT_EDITION_CFORM,
            field_names=[
                'user',
                'name',
                'expected_sales',
                'cost',
                'goal',
                'start',
                'due_date',
                'act_type',
                'segment',
            ],
        )
        build_custom_form_items(
            creation_descriptor=custom_forms.PATTERN_CREATION_CFORM,
            edition_descriptor=custom_forms.PATTERN_EDITION_CFORM,
            field_names=[
                'user',
                'name',
                'average_sales',
                'segment',
            ],
        )
        build_custom_form_items(
            creation_descriptor=custom_forms.STRATEGY_CREATION_CFORM,
            edition_descriptor=custom_forms.STRATEGY_EDITION_CFORM,
            field_names=[
                'user',
                'name',
            ],
        )

        # ---------------------------
        create_searchconf = SearchConfigItem.objects.create_if_needed
        create_searchconf(Act, ['name', 'expected_sales', 'cost', 'goal'])
        create_searchconf(Strategy, ['name'])
        create_searchconf(ActObjectivePattern, [], disabled=True)

        # ---------------------------
        SettingValue.objects.get_or_create(
            key_id=setting_keys.orga_approaches_key.id,
            defaults={'value': True},
        )

        # ---------------------------
        Job.objects.get_or_create(
            type_id=creme_jobs.com_approaches_emails_send_type.id,
            defaults={
                'language': settings.LANGUAGE_CODE,
                'periodicity': date_period_registry.get_period('days', 1),
                'status': Job.STATUS_OK,
                # The CommercialApproach field for Activities' CustomForms is not
                # in the default configuration, so a enabled job would be annoying.
                'enabled': False,
            },
        )

        # ---------------------------
        # TODO: move to "not already_populated" section in creme2.4
        if not MenuConfigItem.objects.filter(
                entry_id__startswith='commercial-').exists():
            container = MenuConfigItem.objects.get_or_create(
                entry_id=ContainerEntry.id,
                entry_data={'label': _('Commercial')},
                defaults={'order': 30},
            )[0]

            create_mitem = MenuConfigItem.objects.create
            create_mitem(entry_id=menu.ActsEntry.id,
                         order=50,
                         parent=container)
            create_mitem(entry_id=menu.StrategiesEntry.id,
                         order=55,
                         parent=container)
            create_mitem(entry_id=menu.SegmentsEntry.id,
                         order=60,
                         parent=container)
            create_mitem(entry_id=menu.PatternsEntry.id,
                         order=70,
                         parent=container)

            directory = MenuConfigItem.objects.filter(
                entry_id=ContainerEntry.id,
                entry_data={
                    'label': _('Directory')
                },
            ).first()
            if directory is not None:
                create_mitem(entry_id=menu.SalesmenEntry.id,
                             order=100,
                             parent=directory)

            creations = MenuConfigItem.objects.filter(
                entry_id=ContainerEntry.id,
                entry_data={
                    'label': _('+ Creation')
                },
            ).first()
            if creations is not None:
                create_mitem(entry_id=menu.ActCreationEntry.id,
                             order=40,
                             parent=creations)

        # ---------------------------
        if not already_populated:
            ButtonMenuItem.objects.create_if_needed(
                button=buttons.CompleteGoalButton,
                order=60,
            )

            TOP = BrickDetailviewLocation.TOP
            RIGHT = BrickDetailviewLocation.RIGHT
            LEFT = BrickDetailviewLocation.LEFT

            # BrickDetailviewLocation.objects.multi_create(
            #     defaults={'brick': bricks.ApproachesBrick, 'order': 10, 'zone': RIGHT},
            #     data=[
            #         {},  # default configuration
            #         {'model': Contact},
            #         {'model': Organisation},
            #     ]
            # )

            BrickDetailviewLocation.objects.multi_create(
                defaults={
                    'model': Act,
                    'zone': LEFT
                },
                data=[
                    {
                        'order': 5
                    },  # generic information brick
                    {
                        'brick': bricks.ActObjectivesBrick,
                        'order': 10
                    },
                    {
                        'brick': bricks.RelatedOpportunitiesBrick,
                        'order': 20
                    },
                    {
                        'brick': core_bricks.CustomFieldsBrick,
                        'order': 40
                    },
                    {
                        'brick': core_bricks.PropertiesBrick,
                        'order': 450
                    },
                    {
                        'brick': core_bricks.RelationsBrick,
                        'order': 500
                    },
                    {
                        'brick': core_bricks.HistoryBrick,
                        'order': 20,
                        'zone': RIGHT
                    },
                ],
            )
            BrickDetailviewLocation.objects.multi_create(
                defaults={
                    'model': ActObjectivePattern,
                    'zone': LEFT
                },
                data=[
                    {
                        'brick': bricks.PatternComponentsBrick,
                        'order': 10,
                        'zone': TOP
                    },
                    {
                        'order': 5
                    },
                    {
                        'brick': core_bricks.CustomFieldsBrick,
                        'order': 40
                    },
                    {
                        'brick': core_bricks.PropertiesBrick,
                        'order': 450
                    },
                    {
                        'brick': core_bricks.RelationsBrick,
                        'order': 500
                    },
                    {
                        'brick': core_bricks.HistoryBrick,
                        'order': 20,
                        'zone': RIGHT
                    },
                ],
            )
            BrickDetailviewLocation.objects.multi_create(
                defaults={
                    'model': Strategy,
                    'zone': LEFT
                },
                data=[
                    {
                        'brick': bricks.SegmentDescriptionsBrick,
                        'order': 10,
                        'zone': TOP
                    },
                    {
                        'order': 5
                    },
                    {
                        'brick': core_bricks.CustomFieldsBrick,
                        'order': 40
                    },
                    {
                        'brick': bricks.EvaluatedOrgasBrick,
                        'order': 50
                    },
                    {
                        'brick': bricks.AssetsBrick,
                        'order': 60
                    },
                    {
                        'brick': bricks.CharmsBrick,
                        'order': 70
                    },
                    {
                        'brick': core_bricks.PropertiesBrick,
                        'order': 450
                    },
                    {
                        'brick': core_bricks.RelationsBrick,
                        'order': 500
                    },
                    {
                        'brick': core_bricks.HistoryBrick,
                        'order': 20,
                        'zone': RIGHT
                    },
                ],
            )

            if apps.is_installed('creme.assistants'):
                logger.info('Assistants app is installed '
                            '=> we use the assistants blocks on detail views')

                from creme.assistants import bricks as a_bricks

                for model in (Act, ActObjectivePattern, Strategy):
                    BrickDetailviewLocation.objects.multi_create(
                        defaults={
                            'model': model,
                            'zone': RIGHT
                        },
                        data=[
                            {
                                'brick': a_bricks.TodosBrick,
                                'order': 100
                            },
                            {
                                'brick': a_bricks.MemosBrick,
                                'order': 200
                            },
                            {
                                'brick': a_bricks.AlertsBrick,
                                'order': 300
                            },
                            {
                                'brick': a_bricks.UserMessagesBrick,
                                'order': 400
                            },
                        ],
                    )

            if apps.is_installed('creme.documents'):
                # logger.info("Documents app is installed
                # => we use the documents blocks on Strategy's detail views")

                from creme.documents.bricks import LinkedDocsBrick

                BrickDetailviewLocation.objects.multi_create(
                    defaults={
                        'brick': LinkedDocsBrick,
                        'order': 600,
                        'zone': RIGHT
                    },
                    data=[
                        {
                            'model': Act
                        },
                        {
                            'model': ActObjectivePattern
                        },
                        {
                            'model': Strategy
                        },
                    ],
                )