wbcommission 2.2.1__py2.py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of wbcommission might be problematic. Click here for more details.

Files changed (76) hide show
  1. wbcommission/__init__.py +1 -0
  2. wbcommission/admin/__init__.py +4 -0
  3. wbcommission/admin/accounts.py +22 -0
  4. wbcommission/admin/commission.py +85 -0
  5. wbcommission/admin/rebate.py +7 -0
  6. wbcommission/analytics/__init__.py +0 -0
  7. wbcommission/analytics/marginality.py +181 -0
  8. wbcommission/apps.py +5 -0
  9. wbcommission/dynamic_preferences_registry.py +0 -0
  10. wbcommission/factories/__init__.py +9 -0
  11. wbcommission/factories/commission.py +100 -0
  12. wbcommission/factories/rebate.py +16 -0
  13. wbcommission/filters/__init__.py +7 -0
  14. wbcommission/filters/rebate.py +187 -0
  15. wbcommission/filters/signals.py +44 -0
  16. wbcommission/generators/__init__.py +2 -0
  17. wbcommission/generators/rebate_generator.py +93 -0
  18. wbcommission/migrations/0001_initial.py +299 -0
  19. wbcommission/migrations/0002_commissionrule_remove_accountcustomer_account_and_more.py +395 -0
  20. wbcommission/migrations/0003_alter_commission_account.py +24 -0
  21. wbcommission/migrations/0004_rebate_audit_log.py +19 -0
  22. wbcommission/migrations/0005_alter_rebate_audit_log.py +20 -0
  23. wbcommission/migrations/0006_commissionrule_consider_zero_percent_for_exclusion.py +21 -0
  24. wbcommission/migrations/0007_remove_commission_unique_crm_recipient_account_and_more.py +50 -0
  25. wbcommission/migrations/0008_alter_commission_options_alter_commission_order.py +26 -0
  26. wbcommission/migrations/__init__.py +0 -0
  27. wbcommission/models/__init__.py +9 -0
  28. wbcommission/models/account_service.py +217 -0
  29. wbcommission/models/commission.py +679 -0
  30. wbcommission/models/rebate.py +319 -0
  31. wbcommission/models/signals.py +45 -0
  32. wbcommission/permissions.py +6 -0
  33. wbcommission/reports/__init__.py +0 -0
  34. wbcommission/reports/audit_report.py +51 -0
  35. wbcommission/reports/customer_report.py +299 -0
  36. wbcommission/reports/utils.py +30 -0
  37. wbcommission/serializers/__init__.py +3 -0
  38. wbcommission/serializers/commissions.py +26 -0
  39. wbcommission/serializers/rebate.py +87 -0
  40. wbcommission/serializers/signals.py +27 -0
  41. wbcommission/tests/__init__.py +0 -0
  42. wbcommission/tests/analytics/__init__.py +0 -0
  43. wbcommission/tests/analytics/test_marginality.py +253 -0
  44. wbcommission/tests/conftest.py +89 -0
  45. wbcommission/tests/models/__init__.py +0 -0
  46. wbcommission/tests/models/mixins.py +22 -0
  47. wbcommission/tests/models/test_account_service.py +293 -0
  48. wbcommission/tests/models/test_commission.py +587 -0
  49. wbcommission/tests/models/test_rebate.py +136 -0
  50. wbcommission/tests/signals.py +0 -0
  51. wbcommission/tests/test_permissions.py +66 -0
  52. wbcommission/tests/viewsets/__init__.py +0 -0
  53. wbcommission/tests/viewsets/test_rebate.py +76 -0
  54. wbcommission/urls.py +42 -0
  55. wbcommission/viewsets/__init__.py +7 -0
  56. wbcommission/viewsets/buttons/__init__.py +2 -0
  57. wbcommission/viewsets/buttons/rebate.py +46 -0
  58. wbcommission/viewsets/buttons/signals.py +53 -0
  59. wbcommission/viewsets/commissions.py +21 -0
  60. wbcommission/viewsets/display/__init__.py +5 -0
  61. wbcommission/viewsets/display/commissions.py +21 -0
  62. wbcommission/viewsets/display/rebate.py +117 -0
  63. wbcommission/viewsets/endpoints/__init__.py +4 -0
  64. wbcommission/viewsets/endpoints/commissions.py +0 -0
  65. wbcommission/viewsets/endpoints/rebate.py +21 -0
  66. wbcommission/viewsets/menu/__init__.py +1 -0
  67. wbcommission/viewsets/menu/commissions.py +0 -0
  68. wbcommission/viewsets/menu/rebate.py +13 -0
  69. wbcommission/viewsets/mixins.py +39 -0
  70. wbcommission/viewsets/rebate.py +481 -0
  71. wbcommission/viewsets/titles/__init__.py +1 -0
  72. wbcommission/viewsets/titles/commissions.py +0 -0
  73. wbcommission/viewsets/titles/rebate.py +11 -0
  74. wbcommission-2.2.1.dist-info/METADATA +11 -0
  75. wbcommission-2.2.1.dist-info/RECORD +76 -0
  76. wbcommission-2.2.1.dist-info/WHEEL +5 -0
@@ -0,0 +1 @@
1
+ __version__ = "1.0.0"
@@ -0,0 +1,4 @@
1
+ from .accounts import AccountModelAdmin
2
+ from .commission import CommissionModelAdmin, CommissionTypeModelAdmin
3
+
4
+ # from .rebate import RebateModelAdmin
@@ -0,0 +1,22 @@
1
+ from django.contrib import admin
2
+ from wbcommission.models.rebate import manage_rebate_as_task
3
+ from wbcrm.admin.accounts import AccountModelAdmin as BaseAccountModelAdmin
4
+ from wbcrm.models.accounts import Account
5
+
6
+ from .commission import CommissionTabularInline
7
+
8
+ admin.site.unregister(Account)
9
+
10
+
11
+ @admin.register(Account)
12
+ class AccountModelAdmin(BaseAccountModelAdmin):
13
+ def make_rebates(self, request, queryset):
14
+ for account in queryset:
15
+ manage_rebate_as_task.delay(account.id)
16
+
17
+ def get_assets_under_management(self, request, queryset):
18
+ for account in queryset:
19
+ account.get_assets_under_management()
20
+
21
+ actions = list(BaseAccountModelAdmin.actions) + [make_rebates, get_assets_under_management]
22
+ inlines = BaseAccountModelAdmin.inlines + [CommissionTabularInline]
@@ -0,0 +1,85 @@
1
+ from django.contrib import admin
2
+ from wbcommission.models import (
3
+ Commission,
4
+ CommissionExclusionRule,
5
+ CommissionRole,
6
+ CommissionRule,
7
+ CommissionType,
8
+ )
9
+
10
+
11
+ @admin.register(CommissionType)
12
+ class CommissionTypeModelAdmin(admin.ModelAdmin):
13
+ pass
14
+
15
+
16
+ class CommissionRuleTabularInline(admin.TabularInline):
17
+ ordering = ("timespan__startswith", "assets_under_management_range__startswith")
18
+ fields = (
19
+ "timespan",
20
+ "assets_under_management_range",
21
+ "percent",
22
+ )
23
+ model = CommissionRule
24
+ extra = 0
25
+
26
+
27
+ class CommissionRoleTabularInline(admin.TabularInline):
28
+ model = CommissionRole
29
+ autocomplete_fields = ["person"]
30
+ fields = (
31
+ "person",
32
+ "commission",
33
+ )
34
+ extra = 0
35
+
36
+
37
+ class CommissionTabularInline(admin.TabularInline):
38
+ extra = 0
39
+ model = Commission
40
+ fields = [
41
+ "order",
42
+ "crm_recipient",
43
+ "account_role_type_recipient",
44
+ "portfolio_role_recipient",
45
+ "commission_type",
46
+ "net_commission",
47
+ "is_hidden",
48
+ "exclusion_rule_account_role_type",
49
+ ]
50
+ readonly_fields = ["order"]
51
+ ordering = ["order"]
52
+ autocomplete_fields = ["account", "crm_recipient"]
53
+ show_change_link = True
54
+
55
+
56
+ @admin.register(Commission)
57
+ class CommissionModelAdmin(admin.ModelAdmin):
58
+ list_display = [
59
+ "account",
60
+ "crm_recipient",
61
+ "portfolio_role_recipient",
62
+ "account_role_type_recipient",
63
+ "order",
64
+ "net_commission",
65
+ "commission_type",
66
+ "is_hidden",
67
+ "exclusion_rule_account_role_type",
68
+ ]
69
+
70
+ autocomplete_fields = ["account", "crm_recipient"]
71
+
72
+ inlines = [CommissionRoleTabularInline, CommissionRuleTabularInline]
73
+
74
+
75
+ @admin.register(CommissionExclusionRule)
76
+ class CommissionExclusionRuleAdmin(admin.ModelAdmin):
77
+ list_display = [
78
+ "product",
79
+ "commission_type",
80
+ "account_role_type",
81
+ "timespan",
82
+ "overriding_percent",
83
+ "overriding_net_or_gross_commission",
84
+ ]
85
+ autocomplete_fields = ["product", "account_role_type"]
@@ -0,0 +1,7 @@
1
+ # @admin.register(Rebate)
2
+ # class RebateModelAdmin(admin.ModelAdmin):
3
+ # def has_add_permission(self, request, obj=None):
4
+ # return False
5
+
6
+ # def has_delete_permission(self, request, obj=None):
7
+ # return False
File without changes
@@ -0,0 +1,181 @@
1
+ from datetime import date
2
+ from decimal import Decimal
3
+
4
+ import numpy as np
5
+ import pandas as pd
6
+ from django.db.models import Case, OuterRef, Subquery, Value, When
7
+ from django.db.models.functions import Coalesce
8
+ from wbcommission.models import CommissionType, Rebate
9
+ from wbcore.contrib.currency.models import CurrencyFXRates
10
+ from wbfdm.models import InstrumentPrice
11
+ from wbportfolio.models import Fees
12
+
13
+
14
+ class MarginalityCalculator:
15
+ FEE_MAP = {
16
+ "MANAGEMENT": "management",
17
+ "PERFORMANCE": "performance",
18
+ "PERFORMANCE_CRYSTALIZED": "performance",
19
+ }
20
+
21
+ def __init__(self, products, from_date: date, to_date: date):
22
+ products = products.annotate(
23
+ fx_rate=Coalesce(
24
+ Subquery(
25
+ CurrencyFXRates.objects.filter(
26
+ currency=OuterRef("currency"), date=OuterRef("last_valuation_date")
27
+ ).values("value")[:1]
28
+ ),
29
+ Decimal(1.0),
30
+ )
31
+ )
32
+
33
+ self.fx_rates = (
34
+ pd.DataFrame(products.values_list("id", "fx_rate"), columns=["id", "fx_rate"])
35
+ .set_index("id")["fx_rate"]
36
+ .astype(float)
37
+ )
38
+
39
+ # compute net marginality
40
+ self.df_aum = pd.DataFrame(
41
+ InstrumentPrice.objects.annotate_base_data()
42
+ .filter(instrument__in=products, date__gte=from_date, date__lte=to_date)
43
+ .values_list("calculated", "net_value_usd", "date", "outstanding_shares", "instrument"),
44
+ columns=["calculated", "net_value_usd", "date", "outstanding_shares", "instrument"],
45
+ ).rename(columns={"instrument": "id"})
46
+ self.df_aum["date"] = pd.to_datetime(self.df_aum["date"])
47
+ self.df_aum = (
48
+ self.df_aum.sort_values(by="calculated")
49
+ .groupby(["id", "date"])
50
+ .agg({"net_value_usd": "last", "outstanding_shares": "first"})
51
+ )
52
+ self.df_aum = (self.df_aum.net_value_usd * self.df_aum.outstanding_shares).astype(float)
53
+ self.df_aum = self.df_aum.reindex(
54
+ pd.MultiIndex.from_product(
55
+ [
56
+ self.df_aum.index.levels[0],
57
+ pd.date_range(
58
+ self.df_aum.index.get_level_values("date").min(),
59
+ self.df_aum.index.get_level_values("date").max(),
60
+ ),
61
+ ],
62
+ names=["id", "date"],
63
+ ),
64
+ method="ffill",
65
+ ).dropna()
66
+
67
+ # Build the fees dataframe where product id is the index and colum are the every fees type available and value are the amount.
68
+
69
+ fees = Fees.valid_objects.filter(
70
+ transaction_date__lte=to_date,
71
+ transaction_date__gte=from_date,
72
+ transaction_subtype__in=self.FEE_MAP.keys(),
73
+ linked_product__in=products,
74
+ ).annotate(
75
+ fee_type=Case(
76
+ *[When(transaction_subtype=k, then=Value(v)) for k, v in self.FEE_MAP.items()],
77
+ default=Value("management"),
78
+ )
79
+ )
80
+ self.df_fees = pd.DataFrame(
81
+ fees.values_list("linked_product", "fee_type", "total_value", "transaction_date", "calculated"),
82
+ columns=["linked_product", "fee_type", "total_value", "transaction_date", "calculated"],
83
+ ).rename(columns={"linked_product": "id", "transaction_date": "date"})
84
+ self.df_fees["date"] = pd.to_datetime(self.df_fees["date"])
85
+
86
+ self.df_fees = (
87
+ self.df_fees[["fee_type", "total_value", "id", "date"]]
88
+ .pivot_table(index=["id", "date"], columns="fee_type", values="total_value", aggfunc="sum")
89
+ .astype("float")
90
+ .round(4)
91
+ )
92
+ self.df_fees["total"] = self.df_fees.sum(axis=1)
93
+ self.df_fees = self.df_fees.reindex(self.df_aum.index, fill_value=0)
94
+ self.df_fees = self._rolling_average_monday(self.df_fees)
95
+
96
+ # Build the fees dataframe where product id is the index and colum are the every fees type available and value are the amount.
97
+ self.df_rebates = pd.DataFrame(
98
+ Rebate.objects.filter(date__gte=from_date, date__lte=to_date, product__in=products).values_list(
99
+ "product", "value", "date", "commission_type__key"
100
+ ),
101
+ columns=["product", "value", "date", "commission_type__key"],
102
+ ).rename(columns={"product": "id"})
103
+ self.df_rebates["date"] = pd.to_datetime(self.df_rebates["date"])
104
+
105
+ self.df_rebates = (
106
+ pd.pivot_table(
107
+ self.df_rebates,
108
+ index=["id", "date"],
109
+ columns="commission_type__key",
110
+ values="value",
111
+ aggfunc="sum",
112
+ fill_value=0,
113
+ )
114
+ .astype("float")
115
+ .round(4)
116
+ )
117
+ self.df_rebates = self.df_rebates.reindex(self.df_aum.index, fill_value=0)
118
+ self.df_rebates["total"] = self.df_rebates.sum(axis=1)
119
+ self.df_rebates = self._rolling_average_monday(self.df_rebates)
120
+ # Iniliaze basic column
121
+
122
+ self.empty_column = pd.Series(0.0, dtype="float64", index=self.df_fees.index)
123
+ self._set_basics_statistics()
124
+
125
+ def _set_basics_statistics(self):
126
+ groupby_fees = self.df_fees.groupby(level=0).sum(numeric_only=True)
127
+ groupby_rebates = self.df_rebates.groupby(level=0).sum(numeric_only=True)
128
+ for key in [*CommissionType.objects.values_list("key", flat=True), "total"]:
129
+ fees = groupby_fees.get(key, self.empty_column)
130
+ rebates = groupby_rebates.get(key, self.empty_column)
131
+ fees_usd = fees * self.fx_rates
132
+ rebates_usd = rebates * self.fx_rates
133
+ marginality = fees - rebates
134
+ marginality_usd = fees_usd - rebates_usd
135
+ marginality_percent = (fees - rebates) / fees.replace(0, np.nan)
136
+ marginality_percent_usd = (fees_usd - rebates_usd) / fees_usd.replace(0, np.nan)
137
+
138
+ setattr(self, f"{key}_fees", fees.rename(f"{key}_fees"))
139
+ setattr(self, f"{key}_rebates", rebates.rename(f"{key}_rebates"))
140
+ setattr(self, f"{key}_fees_usd", fees_usd.rename(f"{key}_fees_usd"))
141
+ setattr(self, f"{key}_rebates_usd", rebates_usd.rename(f"{key}_rebates_usd"))
142
+ setattr(self, f"{key}_marginality", marginality.rename(f"{key}_marginality"))
143
+ setattr(self, f"{key}_marginality_usd", marginality_usd.rename(f"{key}_marginality_usd"))
144
+ setattr(self, f"{key}_marginality_percent", marginality_percent.rename(f"{key}_marginality_percent"))
145
+ setattr(
146
+ self,
147
+ f"{key}_marginality_percent_usd",
148
+ marginality_percent_usd.rename(f"{key}_marginality_percent_usd"),
149
+ )
150
+
151
+ def _rolling_average_monday(self, df):
152
+ """
153
+ This utility method take a dataframe and assum the values on Mondays are accumulated over the weekend. So we need to average every Saturday, Sunday and Monday together.
154
+ """
155
+
156
+ monday = df[df.index.get_level_values("date").weekday == 0] / 3
157
+ monday = monday.reindex(df.index, method="bfill")
158
+ df[df.index.get_level_values("date").weekday.isin([5, 6, 0])] = monday[
159
+ df.index.get_level_values("date").weekday.isin([5, 6, 0])
160
+ ]
161
+ return df
162
+
163
+ def get_net_marginality(self, type: str) -> pd.Series:
164
+ return (
165
+ ((self.df_fees.get(type, self.empty_column) - self.df_rebates.get(type, self.empty_column)) / self.df_aum)
166
+ .groupby("id")
167
+ .mean()
168
+ ) * 360
169
+
170
+ def get_aggregated_net_marginality(self, type: str) -> pd.Series:
171
+ # we compute the total net marginality for management for the aggregate function
172
+ total_aum = self.df_aum.groupby(level=1).sum()
173
+ return (
174
+ (
175
+ (
176
+ self.df_fees.get(type, self.empty_column).groupby(level=1).sum()
177
+ - self.df_rebates.get(type, self.empty_column).groupby(level=1).sum()
178
+ )
179
+ / total_aum
180
+ ).mean(axis=0)
181
+ ) * 360
wbcommission/apps.py ADDED
@@ -0,0 +1,5 @@
1
+ from django.apps import AppConfig
2
+
3
+
4
+ class CommissionConfig(AppConfig):
5
+ name = "wbcommission"
File without changes
@@ -0,0 +1,9 @@
1
+ from .commission import (
2
+ AccountTypeRoleCommissionFactory,
3
+ CommissionFactory,
4
+ CommissionRoleFactory,
5
+ PortfolioRoleCommissionFactory,
6
+ CommissionExclusionRuleFactory,
7
+ CommissionTypeFactory,
8
+ )
9
+ from .rebate import RebateFactory
@@ -0,0 +1,100 @@
1
+ from datetime import date
2
+
3
+ import factory
4
+ from psycopg.types.range import DateRange
5
+ from wbcommission.models.commission import (
6
+ Commission,
7
+ CommissionExclusionRule,
8
+ CommissionRole,
9
+ CommissionType,
10
+ )
11
+ from wbportfolio.models.roles import PortfolioRole
12
+
13
+
14
+ class CommissionTypeFactory(factory.django.DjangoModelFactory):
15
+ name = "MANAGEMENT"
16
+ key = factory.LazyAttribute(lambda x: x.name.lower())
17
+
18
+ class Meta:
19
+ model = CommissionType
20
+ django_get_or_create = ["key"]
21
+
22
+
23
+ class CommissionFactory(factory.django.DjangoModelFactory):
24
+ account = factory.SubFactory("wbcrm.factories.AccountFactory")
25
+ crm_recipient = factory.SubFactory("wbcore.contrib.directory.factories.entries.EntryFactory")
26
+
27
+ portfolio_role_recipient = None
28
+ account_role_type_recipient = None
29
+ order = 0
30
+ commission_type = factory.SubFactory(CommissionTypeFactory)
31
+ net_commission = True
32
+ is_hidden = False
33
+
34
+ class Meta:
35
+ model = Commission
36
+
37
+ @factory.post_generation
38
+ def rule_timespan(self, create, extracted, **kwargs):
39
+ if not create:
40
+ return
41
+ if extracted:
42
+ v = self.rules.first()
43
+ v.timespan = extracted
44
+ v.save()
45
+
46
+ @factory.post_generation
47
+ def rule_aum(self, create, extracted, **kwargs):
48
+ if not create:
49
+ return
50
+ if extracted:
51
+ v = self.rules.first()
52
+ v.assets_under_management_range = extracted
53
+ v.save()
54
+
55
+ @factory.post_generation
56
+ def rule_percent(self, create, extracted, **kwargs):
57
+ if not create:
58
+ return
59
+ if extracted:
60
+ v = self.rules.first()
61
+ v.percent = extracted
62
+ v.save()
63
+
64
+
65
+ class PortfolioRoleCommissionFactory(CommissionFactory):
66
+ crm_recipient = None
67
+ account_role_type_recipient = None
68
+ portfolio_role_recipient = factory.Iterator([role_choice[0] for role_choice in PortfolioRole.RoleType.choices])
69
+
70
+ class Meta:
71
+ model = Commission
72
+
73
+
74
+ class AccountTypeRoleCommissionFactory(CommissionFactory):
75
+ crm_recipient = None
76
+ portfolio_role_recipient = None
77
+ account_role_type_recipient = factory.SubFactory("wbcrm.factories.AccountRoleTypeFactory")
78
+
79
+ class Meta:
80
+ model = Commission
81
+
82
+
83
+ class CommissionRoleFactory(factory.django.DjangoModelFactory):
84
+ commission = factory.SubFactory(CommissionFactory)
85
+ person = factory.SubFactory("wbcore.contrib.directory.factories.entries.PersonFactory")
86
+
87
+ class Meta:
88
+ model = CommissionRole
89
+
90
+
91
+ class CommissionExclusionRuleFactory(factory.django.DjangoModelFactory):
92
+ product = factory.SubFactory("wbportfolio.factories.products.ProductFactory")
93
+ commission_type = factory.SubFactory(CommissionTypeFactory)
94
+ overriding_percent = factory.Faker("pydecimal", min_value=0, max_value=1, right_digits=2)
95
+ overriding_net_or_gross_commission = "DEFAULT"
96
+ account_role_type = None
97
+ timespan = DateRange(date.min, date.max)
98
+
99
+ class Meta:
100
+ model = CommissionExclusionRule
@@ -0,0 +1,16 @@
1
+ import factory
2
+ from wbcommission.models import Rebate
3
+
4
+
5
+ class RebateFactory(factory.django.DjangoModelFactory):
6
+ date = factory.Faker("date_object")
7
+
8
+ commission = factory.SubFactory("wbcommission.factories.CommissionFactory")
9
+ account = factory.LazyAttribute(lambda o: o.commission.account)
10
+ commission_type = factory.LazyAttribute(lambda o: o.commission.commission_type)
11
+ product = factory.SubFactory("wbportfolio.factories.ProductFactory")
12
+ recipient = factory.SubFactory("wbcore.contrib.directory.factories.entries.PersonFactory")
13
+ value = factory.Faker("pydecimal", positive=True, max_value=1000000, right_digits=4)
14
+
15
+ class Meta:
16
+ model = Rebate
@@ -0,0 +1,7 @@
1
+ from .rebate import (
2
+ CustomerRebateGroupByFilter,
3
+ RebateDateFilter,
4
+ RebateGroupByFilter,
5
+ RebateMarginalityFilter,
6
+ )
7
+ from .signals import *
@@ -0,0 +1,187 @@
1
+ from wbcommission.models import Rebate
2
+ from wbcommission.models.rebate import RebateGroupbyChoice
3
+ from wbcore import filters as wb_filters
4
+ from wbcore.contrib.directory.models import Company
5
+ from wbcore.filters.defaults import current_quarter_date_range
6
+ from wbcore.pandas.filterset import PandasFilterSetMixin
7
+ from wbfdm.models import ClassificationGroup
8
+ from wbfdm.preferences import get_default_classification_group
9
+ from wbportfolio.filters.transactions.claim import CommissionBaseFilterSet
10
+ from wbportfolio.models import Product
11
+
12
+
13
+ class RebateDateFilter(CommissionBaseFilterSet):
14
+ date = wb_filters.DateRangeFilter(
15
+ method=wb_filters.DateRangeFilter.base_date_range_filter_method,
16
+ label="Date Range",
17
+ required=True,
18
+ clearable=False,
19
+ default=current_quarter_date_range,
20
+ )
21
+
22
+ class Meta:
23
+ model = Rebate
24
+ fields = {
25
+ "date": ["exact"],
26
+ "account": ["exact"],
27
+ "product": ["exact"],
28
+ "recipient": ["exact"],
29
+ "commission_type": ["exact"],
30
+ }
31
+
32
+
33
+ class RebateGroupByFilter(PandasFilterSetMixin, RebateDateFilter):
34
+ group_by = wb_filters.ChoiceFilter(
35
+ label="Group By",
36
+ choices=RebateGroupbyChoice.choices(),
37
+ default=RebateGroupbyChoice.ACCOUNT.name, # typing: ignore
38
+ method=lambda queryset, label, value: queryset,
39
+ clearable=False,
40
+ required=True,
41
+ )
42
+ groupby_classification_group = wb_filters.ModelChoiceFilter(
43
+ default=lambda k, v, f: get_default_classification_group().id,
44
+ method=lambda queryset, label, value: queryset,
45
+ label="Group by Classification Group",
46
+ queryset=ClassificationGroup.objects.all(),
47
+ endpoint=ClassificationGroup.get_representation_endpoint(),
48
+ value_key=ClassificationGroup.get_representation_value_key(),
49
+ label_key=ClassificationGroup.get_representation_label_key(),
50
+ )
51
+
52
+ class Meta:
53
+ model = Rebate
54
+ fields = {"recipient": ["exact"]}
55
+ df_fields = {
56
+ "management__gte": wb_filters.NumberFilter(
57
+ label="Management Fees (USD)", lookup_expr="gte", field_name="management"
58
+ ),
59
+ "management__lte": wb_filters.NumberFilter(
60
+ label="Management Fees (USD)", lookup_expr="lte", field_name="management"
61
+ ),
62
+ "performance__gte": wb_filters.NumberFilter(
63
+ label="Performance Fees (USD)", lookup_expr="gte", field_name="performance"
64
+ ),
65
+ "performance__lte": wb_filters.NumberFilter(
66
+ label="Performance Fees (USD)", lookup_expr="lte", field_name="performance"
67
+ ),
68
+ "total_rebate__gte": wb_filters.NumberFilter(
69
+ label="Total Fees (USD)", lookup_expr="gte", field_name="total_rebate"
70
+ ),
71
+ "total_rebate__lte": wb_filters.NumberFilter(
72
+ label="Total Fees (USD)", lookup_expr="lte", field_name="total_rebate"
73
+ ),
74
+ }
75
+
76
+
77
+ class CustomerRebateGroupByFilter(RebateGroupByFilter):
78
+ product = wb_filters.ModelChoiceFilter(
79
+ label="Product",
80
+ queryset=Product.objects.all(),
81
+ endpoint=Product.get_representation_endpoint(),
82
+ value_key=Product.get_representation_value_key(),
83
+ label_key="{{title}} {{currency_repr}} - {{isin}}",
84
+ )
85
+
86
+ class Meta:
87
+ model = Rebate
88
+ fields = {
89
+ # "price_start" : ["gte", "exact", "lte"],
90
+ # "price_end" : ["gte", "exact", "lte"],
91
+ "account": ["exact"],
92
+ "product": ["exact"],
93
+ "recipient": ["exact"],
94
+ }
95
+
96
+
97
+ class RebateMarginalityFilter(PandasFilterSetMixin, wb_filters.FilterSet):
98
+ date = wb_filters.DateRangeFilter(
99
+ label="Date Range",
100
+ method=wb_filters.DateRangeFilter.base_date_range_filter_method,
101
+ required=True,
102
+ clearable=False,
103
+ default=current_quarter_date_range,
104
+ )
105
+
106
+ bank = wb_filters.ModelMultipleChoiceFilter(
107
+ label="Bank",
108
+ queryset=Company.bank_objects.all(),
109
+ endpoint=Company.get_representation_endpoint(),
110
+ filter_params={"bank_product": True},
111
+ value_key=Company.get_representation_value_key(),
112
+ label_key=Company.get_representation_label_key(),
113
+ method="filter_bank",
114
+ )
115
+
116
+ def filter_bank(self, queryset, name, value):
117
+ if value:
118
+ return queryset.filter(bank__in=value)
119
+ return queryset
120
+
121
+ class Meta:
122
+ model = Product
123
+ fields = {}
124
+ df_fields = {
125
+ "management_fees__gte": wb_filters.NumberFilter(
126
+ field_name="management_fees", lookup_expr="gte", label="Sum Management Fees"
127
+ ),
128
+ "management_rebates__gte": wb_filters.NumberFilter(
129
+ field_name="management_rebates", lookup_expr="gte", label="Sum Management Rebates"
130
+ ),
131
+ "management_marginality__gte": wb_filters.NumberFilter(
132
+ field_name="management_marginality", lookup_expr="gte", label="Marginality Management"
133
+ ),
134
+ "performance_fees__gte": wb_filters.NumberFilter(
135
+ field_name="performance_fees", lookup_expr="gte", label="Sum Performance Fees"
136
+ ),
137
+ "performance_rebates__gte": wb_filters.NumberFilter(
138
+ field_name="performance_rebates", lookup_expr="gte", label="Sum Performance Rebates"
139
+ ),
140
+ "performance_marginality__gte": wb_filters.NumberFilter(
141
+ field_name="performance_marginality", lookup_expr="gte", label="Marginality Performance"
142
+ ),
143
+ "total_fees__gte": wb_filters.NumberFilter(field_name="total_fees", lookup_expr="gte", label="Total Fees"),
144
+ "total_rebates__gte": wb_filters.NumberFilter(
145
+ field_name="total_rebates", lookup_expr="gte", label="Total Rebates"
146
+ ),
147
+ "total_marginality_percent__gte": wb_filters.NumberFilter(
148
+ field_name="total_marginality_percent", lookup_expr="gte", label="Total Marginality"
149
+ ),
150
+ "total_fees_usd__gte": wb_filters.NumberFilter(
151
+ field_name="total_fees_usd", lookup_expr="gte", label="Total Fees"
152
+ ),
153
+ "total_rebates_usd__gte": wb_filters.NumberFilter(
154
+ field_name="total_rebates_usd", lookup_expr="gte", label="Total Rebates"
155
+ ),
156
+ "management_fees__lte": wb_filters.NumberFilter(
157
+ field_name="management_fees", lookup_expr="lte", label="Sum Management Fees"
158
+ ),
159
+ "management_rebates__lte": wb_filters.NumberFilter(
160
+ field_name="management_rebates", lookup_expr="lte", label="Sum Management Rebates"
161
+ ),
162
+ "management_marginality__lte": wb_filters.NumberFilter(
163
+ field_name="management_marginality", lookup_expr="lte", label="Marginality Management"
164
+ ),
165
+ "performance_fees__lte": wb_filters.NumberFilter(
166
+ field_name="performance_fees", lookup_expr="lte", label="Sum Performance Fees"
167
+ ),
168
+ "performance_rebates__lte": wb_filters.NumberFilter(
169
+ field_name="performance_rebates", lookup_expr="lte", label="Sum Performance Rebates"
170
+ ),
171
+ "performance_marginality__lte": wb_filters.NumberFilter(
172
+ field_name="performance_marginality", lookup_expr="lte", label="Marginality Performance"
173
+ ),
174
+ "total_fees__lte": wb_filters.NumberFilter(field_name="total_fees", lookup_expr="lte", label="Total Fees"),
175
+ "total_rebates__lte": wb_filters.NumberFilter(
176
+ field_name="total_rebates", lookup_expr="lte", label="Total Rebates"
177
+ ),
178
+ "total_marginality_percent__lte": wb_filters.NumberFilter(
179
+ field_name="total_marginality_percent", lookup_expr="lte", label="Total Marginality"
180
+ ),
181
+ "total_fees_usd__lte": wb_filters.NumberFilter(
182
+ field_name="total_fees_usd", lookup_expr="lte", label="Total Fees"
183
+ ),
184
+ "total_rebates_usd__lte": wb_filters.NumberFilter(
185
+ field_name="total_rebates_usd", lookup_expr="lte", label="Total Rebates"
186
+ ),
187
+ }