コード例 #1
0
    def test_get_total_won_quote_this_year04(self):
        "'acceptation_date' is hidden + populate_entities()"
        user = self.login()
        quote1, source1, target1 = self.create_quote_n_orgas('Quote1')
        quote2, source2, target2 = self.create_quote_n_orgas('Quote2')

        FieldsConfig.create(Quote,
                            descriptions=[('acceptation_date', {
                                FieldsConfig.HIDDEN: True
                            })])

        # funf = target1.function_fields.get('total_won_quote_this_year')
        funf = function_field_registry.get(Organisation,
                                           'total_won_quote_this_year')

        FieldsConfig.get_4_model(Quote)  # Fill cache

        with self.assertNumQueries(0):
            funf.populate_entities([target1, target2], user)

        with self.assertNumQueries(0):
            total1 = get_total_won_quote_this_year(target1, user)
            total2 = get_total_won_quote_this_year(target2, user)

        msg = _('Error: «Acceptation date» is hidden')
        self.assertEqual(msg, total1)
        self.assertEqual(msg, total2)
コード例 #2
0
    def test_get_4_models(self):
        model1 = FakeContact
        model2 = FakeOrganisation

        h_field1 = 'phone'
        h_field2 = 'url_site'

        create_fc = FieldsConfig.create
        create_fc(model1,
                  descriptions=[(h_field1, {
                      FieldsConfig.HIDDEN: True
                  })])
        create_fc(model2,
                  descriptions=[(h_field2, {
                      FieldsConfig.HIDDEN: True
                  })])

        with self.assertNumQueries(1):
            fconfigs = FieldsConfig.get_4_models([model1, model2])

        self.assertIsInstance(fconfigs, dict)
        self.assertEqual(2, len(fconfigs))

        fc1 = fconfigs.get(model1)
        self.assertIsInstance(fc1, FieldsConfig)
        self.assertEqual(model1, fc1.content_type.model_class())
        self.assertTrue(fc1.is_fieldname_hidden(h_field1))

        self.assertTrue(fconfigs.get(model2).is_fieldname_hidden(h_field2))

        with self.assertNumQueries(0):
            FieldsConfig.get_4_models([model1, model2])

        with self.assertNumQueries(0):
            FieldsConfig.get_4_model(model1)
コード例 #3
0
    def test_get_4_model01(self):
        model = FakeContact
        h_field1 = 'phone'
        h_field2 = 'mobile'
        FieldsConfig.create(
            model,
            descriptions=[
                (h_field1, {
                    FieldsConfig.HIDDEN: True
                }),
                (h_field2, {
                    FieldsConfig.HIDDEN: True
                }),
            ],
        )

        with self.assertNumQueries(1):
            fc = FieldsConfig.get_4_model(model)

        is_hidden = fc.is_fieldname_hidden
        self.assertTrue(is_hidden(h_field1))
        self.assertTrue(is_hidden(h_field2))
        self.assertFalse(is_hidden('description'))

        with self.assertNumQueries(0):  # cache
            FieldsConfig.get_4_model(model)
コード例 #4
0
    def test_get_total_won_quote_last_year03(self):
        "'populate_entities()"
        user = self.login()
        previous_year = self.today_date - timedelta(days=365)

        def set_date(quote):
            quote.acceptation_date = previous_year
            quote.save()

        quote01, source01, target01 = self.create_quote_n_orgas(
            'Quote01', status=self.won_status)
        quote02, source02, target02 = self.create_quote_n_orgas(
            'Quote02', status=self.won_status)

        # Not won status => not used
        quote03 = self.create_quote('Quote #3', source01, target01)
        self.assertFalse(quote03.status.won)

        # Current year => not used
        quote04 = self.create_quote('Quote #4',
                                    source01,
                                    target02,
                                    status=self.won_status)
        quote04.acceptation_date = self.today_date
        quote04.save()

        set_date(quote01)
        set_date(quote02)
        set_date(quote03)

        self._set_managed(source01)
        self._set_managed(source02)

        self.create_line(quote01, 5000, 1)
        self.create_line(quote02, 4000, 1)
        self.create_line(quote03, 500, 1)  # Not used
        self.create_line(quote04, 300, 1)  # Not used

        # funf = target01.function_fields.get('total_won_quote_last_year')
        funf = function_field_registry.get(Organisation,
                                           'total_won_quote_last_year')
        self.assertIsNotNone(funf)

        FieldsConfig.get_4_model(Quote)  # Fill cache
        bool(Organisation.get_all_managed_by_creme())  # Fill cache

        with self.assertNumQueries(2):
            funf.populate_entities([target01, target02], user)

        with self.assertNumQueries(0):
            total1 = funf(target01, user).for_csv()
            total2 = funf(target02, user).for_csv()

        self.assertEqual(number_format('5000.00', use_l10n=True), total1)
        self.assertEqual(number_format('4000.00', use_l10n=True), total2)
コード例 #5
0
    def test_get_total_won_quote_this_year01(self):
        user = self.login()

        def set_date(quote):
            quote.acceptation_date = self.today_date
            quote.save()

        quote01, source, target = self.create_quote_n_orgas(
            'Quote #1', status=self.won_status)
        set_date(quote01)
        self._set_managed(source)

        quote02 = self.create_quote('Quote #2',
                                    source,
                                    target,
                                    status=self.won_status)
        set_date(quote02)

        # Not won status => not used
        quote03 = self.create_quote('Quote #3', source, target)
        self.assertFalse(quote03.status.won)
        set_date(quote03)
        self.create_line(quote03, 500, 1)

        # Previous year => not used
        quote04 = self.create_quote('Quote #4',
                                    source,
                                    target,
                                    status=self.won_status)
        quote04.acceptation_date = self.today_date - timedelta(days=366)
        quote04.save()
        self.create_line(quote04, 300, 1)

        FieldsConfig.get_4_model(Quote)  # Fill cache
        bool(Organisation.get_all_managed_by_creme())  # Fill cache

        with self.assertNumQueries(2):
            total = get_total_won_quote_this_year(target, user)

        self.assertEqual(0, total)

        self.create_line(quote01, 5000, 1)
        self.create_line(quote02, 1000, 1)
        self.assertEqual(6000, get_total_won_quote_this_year(target, user))

        # funf = target.function_fields.get('total_won_quote_this_year')
        funf = function_field_registry.get(Organisation,
                                           'total_won_quote_this_year')
        self.assertIsNotNone(funf)

        val = number_format('6000.00', use_l10n=True)
        self.assertEqual(val, funf(target, user).for_html())
        self.assertEqual(val, funf(target, user).for_csv())
コード例 #6
0
ファイル: persons_tags.py プロジェクト: mrjmad/creme_crm-2.1
def persons_pretty_address(address):
    is_field_hidden = FieldsConfig.get_4_model(address.__class__).is_fieldname_hidden

    with StringIO() as sio:
        write = sio.write

        addr = '' if is_field_hidden('address') else address.address
        if addr:
            write(addr)

        po_box = '' if is_field_hidden('po_box') else address.po_box
        if po_box:
            if sio.tell():
                write('\n')

            write(po_box)

        zipcode = '' if is_field_hidden('zipcode') else address.zipcode
        city    = '' if is_field_hidden('city')    else address.city
        if zipcode or city:
            if sio.tell():
                write('\n')

            if not zipcode:
                write(city)
            elif not city:
                write(zipcode)
            else:
                write(city)
                write(' ')
                write(zipcode)

        return sio.getvalue()
コード例 #7
0
ファイル: address.py プロジェクト: mrjmad/creme_crm-2.1
 def info_field_names(cls):
     is_field_hidden = FieldsConfig.get_4_model(cls).is_field_hidden
     excluded = {'id', 'content_type', 'object'}  # TODO: just exclude not viewable ?
     return tuple(f.name
                     for f in cls._meta.fields
                         if f.name not in excluded and not is_field_hidden(f)
                 )
コード例 #8
0
ファイル: address.py プロジェクト: mrjmad/creme_crm-2.1
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)

        # TODO: should be in the view ?
        field_name = self.field_name
        if FieldsConfig.get_4_model(self._entity.__class__).is_fieldname_hidden(field_name):
            raise ConflictError('"{}" is hidden & so it cannot be edited'.format(field_name))
コード例 #9
0
def get_merge_form_builder(model, base_form_class=_PersonMergeForm):
    address_field_names = [*Address.info_field_names()]
    # TODO: factorise with lv_import.py
    try:
        address_field_names.remove('name')
    except ValueError:
       pass

    attrs = {'_address_field_names': address_field_names}

    get_field = Address._meta.get_field
    fields = [get_field(field_name) for field_name in address_field_names]

    is_hidden = FieldsConfig.get_4_model(model).is_fieldname_hidden

    def add_fields(attr_name, prefix):
        fnames = []

        if not is_hidden(attr_name):
            for field in fields:
                form_fieldname = prefix + field.name
                attrs[form_fieldname] = mergefield_factory(field)
                fnames.append(form_fieldname)

        return fnames

    billing_address_fnames  = add_fields('billing_address', _BILL_PREFIX)
    shipping_address_fnames = add_fields('shipping_address', _SHIP_PREFIX)

    attrs['blocks'] = MergeEntitiesBaseForm.blocks.new(
        ('billing_address',  _('Billing address'),  billing_address_fnames),
        ('shipping_address', _('Shipping address'), shipping_address_fnames),
    )

    return type('PersonMergeForm', (base_form_class,), attrs)
コード例 #10
0
    def test_get_total_won_quote_this_year02(self):
        "'acceptation_date' is hidden"
        user = self.login()

        quote, source, target = self.create_quote_n_orgas('Quote #1')
        FieldsConfig.create(Quote,
                            descriptions=[('acceptation_date', {FieldsConfig.HIDDEN: True})]
                           )

        funf = function_field_registry.get(Organisation, 'total_won_quote_this_year')

        FieldsConfig.get_4_model(Quote)  # Fill cache

        with self.assertNumQueries(0):
            total = funf(target, user).for_csv()

        self.assertEqual(_('Error: «Acceptation date» is hidden'), total)
コード例 #11
0
    def test_get_4_model03(self):
        "Cache not created"
        model = FakeContact
        FieldsConfig.create(
            model,
            descriptions=[('phone', {
                FieldsConfig.HIDDEN: True
            })],
        )

        set_global_info(per_request_cache=None)

        with self.assertNumQueries(1):
            FieldsConfig.get_4_model(model)

        with self.assertNumQueries(0):
            FieldsConfig.get_4_model(model)
コード例 #12
0
 def finalize_recipient_field(name, model):
     if FieldsConfig.get_4_model(model).is_fieldname_hidden('email'):
         self.fields[name] = CharField(
                 label=self.fields[name].label,
                 required=False, widget=Label,
                 initial=ugettext('Beware: the field «Email address» is hidden ;'
                                  ' please contact your administrator.'
                                 ),
             )
コード例 #13
0
    def test_get_total_won_quote_last_year02(self):
        "'acceptation_date' is hidden"
        user = self.login()
        quote, source, target = self.create_quote_n_orgas("YOLO")

        FieldsConfig.create(Quote,
                            descriptions=[('acceptation_date', {FieldsConfig.HIDDEN: True})]
                           )

        quote.acceptation_date = self.today_date
        self._set_managed(source)

        FieldsConfig.get_4_model(Quote)  # Fill cache

        with self.assertNumQueries(0):
            total = get_total_won_quote_last_year(target, user)

        self.assertEqual(_('Error: «Acceptation date» is hidden'), total)
コード例 #14
0
    def test_get_4_model02(self):
        "No query for model which cannot be registered."
        ContentType.objects.get_for_model(FakeCivility)  # Fill cache if needed

        with self.assertNumQueries(0):
            # fc = FieldsConfig.get_4_model(CremeEntity)
            fc = FieldsConfig.get_4_model(FakeCivility)

        self.assertFalse([*fc.hidden_fields])
コード例 #15
0
    def content_type(self, ct):
        EntityCellsField.content_type.fset(self, ct)

        if ct is not None:
            builders = self._builders
            widget = self.widget
            model = ct.model_class()

            # Related ----------------------------------------------------------
            widget.related_entities = related_choices = []

            for related_name, related_vname in Report.get_related_fields_choices(model):
                rel_id = _RELATED_PREFIX + related_name
                related_choices.append((rel_id, related_vname))
                builders[rel_id] = ReportHandsField._build_4_related

            # Aggregates -------------------------------------------------------
            widget.regular_aggregates = reg_agg_choices = []
            widget.custom_aggregates  = cust_agg_choices = []
            authorized_fields       = field_aggregation_registry.authorized_fields
            authorized_customfields = field_aggregation_registry.authorized_customfields

            fconf = FieldsConfig.get_4_model(model)
            non_hiddable_aggnames = {
                cell.value
                for cell in self._non_hiddable_cells
                if cell.type_id == _EntityCellAggregate.type_id
            }

            for aggregate in field_aggregation_registry.aggregations:
                pattern = aggregate.pattern
                title   = aggregate.title

                for f_name, f_vname in ModelFieldEnumerator(
                    model, deep=0,
                ).filter(
                    (lambda f, deep: isinstance(f, authorized_fields)),
                    viewable=True,
                ).choices():
                    agg_name = pattern.format(f_name)

                    if fconf.is_fieldname_hidden(f_name) and agg_name not in non_hiddable_aggnames:
                        continue

                    agg_id = _REGULAR_AGG_PREFIX + agg_name
                    reg_agg_choices.append((agg_id, '{} - {}'.format(title, f_vname)))

                    builders[agg_id] = ReportHandsField._build_4_regular_aggregate

                for cf in self._custom_fields:
                    if cf.field_type in authorized_customfields:
                        agg_id = _CUSTOM_AGG_PREFIX + pattern.format(cf.id)
                        cust_agg_choices.append((agg_id, '{} - {}'.format(title, cf.name)))
                        builders[agg_id] = ReportHandsField._build_4_custom_aggregate
コード例 #16
0
def get_total_won_quote_last_year(entity, user):
    if FieldsConfig.get_4_model(Quote).is_fieldname_hidden('acceptation_date'):
        return ugettext('Error: «Acceptation date» is hidden')

    return sum_totals_no_vat(
        Quote,
        entity,
        user,
        status__won=True,
        acceptation_date__year=datetime.date.today().year - 1,
    )
コード例 #17
0
def get_total_won_quote_this_year(entity, user):
    # TODO: factorise (decorator in creme_core ?)
    if FieldsConfig.get_4_model(Quote).is_fieldname_hidden('acceptation_date'):
        return ugettext('Error: «Acceptation date» is hidden')

    return sum_totals_no_vat(
        Quote,
        entity,
        user,
        status__won=True,
        acceptation_date__year=datetime.date.today().year,
    )
コード例 #18
0
def get_total_won_quote_this_year_multi(entities, user):
    # TODO: factorise
    if FieldsConfig.get_4_model(Quote).is_fieldname_hidden('acceptation_date'):
        msg = ugettext('Error: «Acceptation date» is hidden')
        return ((entity, msg) for entity in entities)

    return sum_totals_no_vat_multi(
        Quote,
        entities,
        user,
        status__won=True,
        acceptation_date__year=datetime.date.today().year,
    )
コード例 #19
0
    def test_get_weighted_sales02(self):
        "With field 'estimated_sales' hidden with FieldsConfig"
        user = self.login()

        FieldsConfig.create(Opportunity,
                            descriptions=[('estimated_sales', {
                                FieldsConfig.HIDDEN: True
                            })])

        opportunity = self._create_opportunity_n_organisations()[0]

        FieldsConfig.get_4_model(Opportunity)

        # with self.assertNumQueries(0):
        #     w_sales = opportunity.get_weighted_sales()
        #
        # self.assertEqual(_('Error: «Estimated sales» is hidden'), w_sales)
        funf = function_field_registry.get(Opportunity, 'get_weighted_sales')

        with self.assertNumQueries(0):
            w_sales = funf(opportunity, user).for_html()

        self.assertEqual(_('Error: «Estimated sales» is hidden'), w_sales)
コード例 #20
0
def set_default(request, payment_information_id, billing_id):
    pi = get_object_or_404(PaymentInformation, pk=payment_information_id)
    # billing_doc = get_object_or_404(CremeEntity, pk=billing_id).get_real_entity()
    entity = get_object_or_404(CremeEntity.objects.select_for_update(), pk=billing_id)
    user = request.user

    real_model = entity.entity_type.model_class()

    # if not isinstance(billing_doc, (billing.get_invoice_model(), billing.get_quote_model(),
    #                                 billing.get_sales_order_model(), billing.get_credit_note_model(),
    #                                 billing.get_template_base_model(),
    #                                )
    #                  ):
    if real_model not in {billing.get_invoice_model(),
                          billing.get_quote_model(),
                          billing.get_sales_order_model(),
                          billing.get_credit_note_model(),
                          billing.get_template_base_model(),
                         }:
        raise Http404('This entity is not a billing document')

    # if FieldsConfig.get_4_model(billing_doc.__class__).is_fieldname_hidden('payment_info'):
    if FieldsConfig.get_4_model(real_model).is_fieldname_hidden('payment_info'):
        raise ConflictError('The field "payment_info" is hidden.')

    billing_doc = entity.get_real_entity()

    organisation = pi.get_related_entity()
    user.has_perm_to_view_or_die(organisation)
    user.has_perm_to_link_or_die(organisation)

    user.has_perm_to_change_or_die(billing_doc)

    inv_orga_source = billing_doc.get_source()
    if not inv_orga_source or inv_orga_source.id != organisation.id:
        raise Http404('No organisation in this invoice.')

    billing_doc.payment_info = pi
    billing_doc.save()

    return {}
コード例 #21
0
ファイル: mass_import.py プロジェクト: mrjmad/creme_crm-2.1
def get_massimport_form_builder(header_dict,
                                choices,
                                model,
                                base_form=_PersonMassImportForm):
    address_field_names = [*Address.info_field_names()
                           ]  # TODO: remove not-editable fields ??
    try:
        address_field_names.remove('name')
    except ValueError:
        pass

    attrs = {'_address_field_names': address_field_names}

    get_field = Address._meta.get_field
    fields = [get_field(field_name) for field_name in address_field_names]

    is_hidden = FieldsConfig.get_4_model(model).is_fieldname_hidden

    def add_fields(attr_name, prefix):
        fnames = []
        hidden = is_hidden(attr_name)

        if not hidden:
            for field in fields:
                form_fieldname = prefix + field.name
                attrs[form_fieldname] = extractorfield_factory(
                    field, header_dict, choices)
                fnames.append(form_fieldname)

        attrs['_{}_hidden'.format(attr_name)] = hidden

        return fnames

    billing_address_fnames = add_fields('billing_address', _BILL_PREFIX)
    shipping_address_fnames = add_fields('shipping_address', _SHIP_PREFIX)

    attrs['blocks'] = ImportForm4CremeEntity.blocks.new(
        ('billing_address', _('Billing address'), billing_address_fnames),
        ('shipping_address', _('Shipping address'), shipping_address_fnames))

    return type('PersonMassImportForm', (base_form, ), attrs)
コード例 #22
0
    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        instance = self.instance
        selected_fnames = [sf.name for sf in instance.searchfields]
        # TODO: work with Fields instead of Field names + split()...
        not_hiddable_fnames = OrderedSet(
            fname.split('__', 1)[0] for fname in selected_fnames)
        is_hidden = FieldsConfig.get_4_model(
            instance.content_type.model_class()).is_fieldname_hidden

        def keep_field(name):
            root_name = name.split('__', 1)[0]

            return not is_hidden(root_name) or root_name in not_hiddable_fnames

        fields_f = self.fields['fields']
        fields_f.choices = [
            choice for choice in self.instance.get_modelfields_choices()
            if keep_field(choice[0])
        ]
        fields_f.initial = selected_fnames
コード例 #23
0
    def post(self, request, *args, **kwargs):
        pi = self.get_payment_information()
        billing_doc = self.get_related_entity()

        if FieldsConfig.get_4_model(type(billing_doc))\
                       .is_fieldname_hidden(self.payment_info_fk):
            raise ConflictError('The field "{}" is hidden.'.format(
                self.payment_info_fk))

        user = request.user
        organisation = pi.get_related_entity()
        user.has_perm_to_view_or_die(organisation)
        user.has_perm_to_link_or_die(organisation)

        source = billing_doc.get_source()
        if not source or source.id != organisation.id:
            raise ConflictError('The related organisation does not match.')

        billing_doc.payment_info = pi
        billing_doc.save()

        return HttpResponse()
コード例 #24
0
    def __call__(self, entity, user):
        is_hidden = FieldsConfig.get_4_model(
            entity.__class__).is_fieldname_hidden

        # if is_hidden('estimated_sales'):
        #     value = gettext('Error: «Estimated sales» is hidden')
        # elif is_hidden('chance_to_win'):
        #     value = gettext(r'Error: «% of chance to win» is hidden')
        # else:
        #     value = (entity.estimated_sales or 0) * (entity.chance_to_win or 0) / 100.0
        #
        # return self.result_type(value)
        if is_hidden('estimated_sales'):
            return FunctionFieldResult(
                gettext('Error: «Estimated sales» is hidden'))

        if is_hidden('chance_to_win'):
            return FunctionFieldResult(
                gettext(r'Error: «% of chance to win» is hidden'))

        return self.result_type((entity.estimated_sales or 0) *
                                (entity.chance_to_win or 0) / 100.0)
コード例 #25
0
    def __init__(self, contact):
        is_hidden = FieldsConfig.get_4_model(
            contact.__class__).is_fieldname_hidden

        def get_field_value(fname, default=None):
            return default if is_hidden(fname) else getattr(
                contact, fname, default)

        self.first_name = get_field_value('first_name', None) or ''
        self.last_name = get_field_value('last_name', '')
        self.civility = get_field_value('civility')
        self.phone = get_field_value('phone')
        self.mobile = get_field_value('mobile')
        self.fax = get_field_value('fax')
        self.email = get_field_value('email')
        self.url = get_field_value('url_site')

        # TODO: manage several employers
        self.employer = contact.get_employers().first()

        self._address_field_names = {*Address.info_field_names()}
        self.addresses = Address.objects.filter(
            object_id=contact.id).order_by('id')
コード例 #26
0
    def test_get_4_model02(self):
        "No query for model which cannot be registered"
        with self.assertNumQueries(0):
            fc = FieldsConfig.get_4_model(CremeEntity)

        self.assertFalse(list(fc.hidden_fields))
コード例 #27
0
ファイル: statistics.py プロジェクト: mrjmad/creme_crm-2.1
    def __call__(self):
        stats = []
        opp_model = self.opp_model

        if FieldsConfig.get_4_model(opp_model).is_fieldname_hidden(
                'closing_date'):
            stats.append(str(self.invalid_message))
        else:
            # TODO: use this previous code when there is only one managed organisation ??
            # # filter_opp = partial(
            # #     opp_model.objects.filter,
            # #     relations__type_id=self.relation_type_id,
            # #     closing_date__gte=date.today().replace(month=1, day=1),
            # # )
            #
            # for orga in self.orga_model.get_all_managed_by_creme():
            #     # won_count = filter_opp(sales_phase__won=True,
            #     #                        relations__object_entity_id=orga.id,
            #     #                       ).count()
            #     # lost_count = filter_opp(sales_phase__lost=True,
            #     #                         relations__object_entity_id=orga.id,
            #     #                        ).count()
            #
            #     agg = opp_model.objects \
            #              .annotate(relations_w_orga=FilteredRelation(
            #                             'relations',
            #                             condition=Q(relations__object_entity_id=orga.id)
            #                         )
            #                       ) \
            #              .filter(relations_w_orga__type_id=self.relation_type_id,
            #                      closing_date__gte=date.today().replace(month=1, day=1),
            #                     )\
            #              .aggregate(
            #                 won=Count('pk', filter=Q(sales_phase__won=True)),
            #                 lost=Count('pk', filter=Q(sales_phase__lost=True)),
            #              )
            #     won_count = agg['won']
            #     lost_count = agg['lost']
            #
            #     if won_count or lost_count:
            #         stats.append(
            #             self.message_format.format(
            #                 organisation=orga,
            #                 won_stats=ungettext('{count} won opportunity',
            #                                     '{count} won opportunities',
            #                                     won_count
            #                                    ).format(count=won_count),
            #                 lost_stats=ungettext('{count} lost opportunity',
            #                                      '{count} lost opportunities',
            #                                      lost_count
            #                                     ).format(count=lost_count),
            #             )
            #         )
            # TODO: query by chunks if there are lots of managed Organisation ?
            mngd_orgas = [*self.orga_model.objects.filter_managed_by_creme()]
            mngd_orga_ids = [o.id for o in mngd_orgas]

            agg_kwargs = {}
            for orga_id in mngd_orga_ids:
                agg_kwargs['won_{}'.format(orga_id)] = Count(
                    'relations_w_orga__object_entity_id',
                    filter=Q(
                        relations_w_orga__object_entity=orga_id,
                        sales_phase__won=True,
                    ),
                )
                agg_kwargs['lost_{}'.format(orga_id)] = Count(
                    'relations_w_orga__object_entity_id',
                    filter=Q(
                        relations_w_orga__object_entity=orga_id,
                        sales_phase__lost=True,
                    ),
                )

            agg = opp_model.objects \
                           .annotate(relations_w_orga=FilteredRelation(
                                'relations',
                                condition=Q(relations__object_entity_id__in=mngd_orga_ids),
                           )).filter(
                                relations_w_orga__type_id=self.relation_type_id,
                                closing_date__gte=date.today().replace(month=1, day=1),
                           ).aggregate(**agg_kwargs)

            for orga in mngd_orgas:
                orga_id = orga.id
                won_count = agg['won_{}'.format(orga_id)]
                lost_count = agg['lost_{}'.format(orga_id)]

                if won_count or lost_count:
                    stats.append(
                        self.message_format.format(
                            organisation=orga,
                            won_stats=ngettext(
                                '{count} won opportunity',
                                '{count} won opportunities',
                                won_count).format(count=won_count),
                            lost_stats=ngettext(
                                '{count} lost opportunity',
                                '{count} lost opportunities',
                                lost_count).format(count=lost_count),
                        ))

        return stats