wbportfolio 1.50.9__py2.py3-none-any.whl → 1.50.11__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 wbportfolio might be problematic. Click here for more details.

@@ -123,7 +123,7 @@ class DateFilterMixin:
123
123
 
124
124
  class AssetPositionFilter(wb_filters.FilterSet):
125
125
  date = wb_filters.DateFilter(
126
- label="Date", lookup_expr="exact", field_name="date", default=get_latest_asset_position, required=True
126
+ label="Date", lookup_expr="exact", field_name="date", initial=get_latest_asset_position, required=True
127
127
  )
128
128
 
129
129
  underlying_instrument__is_cash = wb_filters.BooleanFilter(
@@ -178,7 +178,7 @@ class AssetPositionFilter(wb_filters.FilterSet):
178
178
  filter_params=get_asset_filter_param,
179
179
  )
180
180
  hide_empty_position = wb_filters.BooleanFilter(
181
- default=False, method="boolean_hide_empty_position", label="Hide Empty Position"
181
+ initial=False, method="boolean_hide_empty_position", label="Hide Empty Position"
182
182
  )
183
183
 
184
184
  total_value_fx_usd = wb_filters.NumberFilter(label="Total Value ($)")
@@ -261,7 +261,7 @@ class AssetPositionFilter(wb_filters.FilterSet):
261
261
 
262
262
  class AssetPositionPortfolioFilter(AssetPositionFilter):
263
263
  portfolio_instrument = portfolio = None
264
- aggregate = wb_filters.BooleanFilter(default=False, label="Aggregate", method="filter_aggregate")
264
+ aggregate = wb_filters.BooleanFilter(initial=False, required=True, label="Aggregate", method="filter_aggregate")
265
265
 
266
266
  def filter_aggregate(self, queryset, name, value):
267
267
  if value:
@@ -314,14 +314,14 @@ class AssetPositionInstrumentFilter(AssetPositionFilter):
314
314
  label="Date",
315
315
  lookup_expr="exact",
316
316
  field_name="date",
317
- default=get_latest_asset_position,
317
+ initial=get_latest_asset_position,
318
318
  method="filter_date",
319
319
  required=True,
320
320
  )
321
321
  filter_last_positions = wb_filters.BooleanFilter(label="Fetch last position", method="fake_filter")
322
322
 
323
323
  hide_aggregated_position = wb_filters.BooleanFilter(
324
- default=False, method="boolean_hide_aggregated_position", label="Hide Position from Aggregated Product"
324
+ initial=False, method="boolean_hide_aggregated_position", label="Hide Position from Aggregated Product"
325
325
  )
326
326
 
327
327
  def boolean_hide_aggregated_position(self, queryset, name, value):
@@ -368,7 +368,7 @@ class CashPositionPortfolioFilterSet(wb_filters.FilterSet):
368
368
  )
369
369
 
370
370
  date = wb_filters.DateFilter(
371
- label="Date", lookup_expr="exact", field_name="date", default=get_latest_asset_position, required=True
371
+ label="Date", lookup_expr="exact", field_name="date", initial=get_latest_asset_position, required=True
372
372
  )
373
373
 
374
374
  class Meta:
@@ -394,14 +394,14 @@ class DistributionFilter(wb_filters.FilterSet):
394
394
  label="Date",
395
395
  lookup_expr="exact",
396
396
  field_name="date",
397
- default=latest_portfolio_date_based_on_instrument,
397
+ initial=latest_portfolio_date_based_on_instrument,
398
398
  required=True,
399
399
  )
400
400
 
401
401
  group_by = wb_filters.ChoiceFilter(
402
402
  label="Group By",
403
403
  choices=AssetPositionGroupBy.choices(),
404
- default=AssetPositionGroupBy.INDUSTRY.name,
404
+ initial=AssetPositionGroupBy.INDUSTRY.name,
405
405
  method="fake_filter",
406
406
  clearable=False,
407
407
  required=True,
@@ -414,13 +414,13 @@ class DistributionFilter(wb_filters.FilterSet):
414
414
  value_key=Portfolio.get_representation_value_key(),
415
415
  label_key=Portfolio.get_representation_label_key(),
416
416
  filter_params=get_portfolio_filter_params,
417
- default=get_portfolio_default,
417
+ initial=get_portfolio_default,
418
418
  required=True,
419
419
  clearable=False,
420
420
  )
421
421
 
422
422
  group_by_classification_group = wb_filters.ModelChoiceFilter(
423
- default=lambda k, v, f: get_default_classification_group().id,
423
+ initial=lambda k, v, f: get_default_classification_group().id,
424
424
  method=lambda queryset, label, value: queryset,
425
425
  label="Group by Classification Group",
426
426
  queryset=ClassificationGroup.objects.all(),
@@ -445,7 +445,7 @@ class ContributionChartFilter(wb_filters.FilterSet):
445
445
  label="Date Range",
446
446
  required=True,
447
447
  clearable=False,
448
- default=current_financial_month,
448
+ initial=current_financial_month,
449
449
  )
450
450
  hedged_currency = wb_filters.ModelChoiceFilter(
451
451
  label="Hedged Currency",
@@ -454,7 +454,7 @@ class ContributionChartFilter(wb_filters.FilterSet):
454
454
  value_key=Currency.get_representation_value_key(),
455
455
  label_key=Currency.get_representation_label_key(),
456
456
  method=lambda queryset, label, value: queryset,
457
- default=get_default_hedged_currency,
457
+ initial=get_default_hedged_currency,
458
458
  )
459
459
 
460
460
  class Meta:
@@ -463,7 +463,9 @@ class ContributionChartFilter(wb_filters.FilterSet):
463
463
 
464
464
 
465
465
  class CompositionContributionChartFilter(ContributionChartFilter):
466
- show_lookthrough = wb_filters.BooleanFilter(label="Show Lookthrough", default=False, method="fake_filter")
466
+ show_lookthrough = wb_filters.BooleanFilter(
467
+ label="Show Lookthrough", initial=False, required=True, method="fake_filter"
468
+ )
467
469
 
468
470
 
469
471
  class AssetPositionUnderlyingInstrumentChartFilter(DateFilterMixin, wb_filters.FilterSet):
@@ -481,7 +483,7 @@ class AssetPositionUnderlyingInstrumentChartFilter(DateFilterMixin, wb_filters.F
481
483
 
482
484
 
483
485
  class CompositionModelPortfolioPandasFilter(PandasFilterSetMixin, wb_filters.FilterSet):
484
- date = wb_filters.DateFilter(label="Date", lookup_expr="exact", default=get_latest_asset_position, required=True)
486
+ date = wb_filters.DateFilter(label="Date", lookup_expr="exact", initial=get_latest_asset_position, required=True)
485
487
 
486
488
  class Meta:
487
489
  model = AssetPosition
@@ -12,7 +12,7 @@ class AssetsAndNetNewMoneyProgressionFilterSet(filters.FilterSet):
12
12
  method=lambda queryset, label, value: queryset,
13
13
  required=True,
14
14
  clearable=False,
15
- default=financial_year_to_date,
15
+ initial=financial_year_to_date,
16
16
  )
17
17
 
18
18
  product = filters.ModelChoiceFilter(
@@ -8,12 +8,12 @@ from .assets import get_latest_asset_position
8
8
 
9
9
  class ESGMetricAggregationPortfolioPandasFilterSet(wb_filters.FilterSet):
10
10
  date = wb_filters.DateFilter(
11
- label="Date", lookup_expr="exact", field_name="date", default=get_latest_asset_position, required=True
11
+ label="Date", lookup_expr="exact", field_name="date", initial=get_latest_asset_position, required=True
12
12
  )
13
13
 
14
14
  esg_aggregation = wb_filters.ChoiceFilter(
15
15
  choices=ESGAggregation.choices(),
16
- default=ESGAggregation.GHG_EMISSIONS_SCOPE_1.name,
16
+ initial=ESGAggregation.GHG_EMISSIONS_SCOPE_1.name,
17
17
  required=True,
18
18
  method="fake_filter",
19
19
  )
@@ -21,20 +21,20 @@ class PerformancePandasFilter(PandasFilterSetMixin, BaseProductFilterSet):
21
21
  AUM = "AUM", "AUM"
22
22
  PRICE = "PRICE", "Price"
23
23
 
24
- is_forex_fix = wb_filters.BooleanFilter(label="Fix Forex rate", method="fake_filter", default=False)
24
+ is_forex_fix = wb_filters.BooleanFilter(label="Fix Forex rate", method="fake_filter", initial=False, required=True)
25
25
 
26
26
  date = wb_filters.FinancialPerformanceDateRangeFilter(
27
27
  label="Date Range",
28
28
  method=lambda queryset, label, value: queryset,
29
29
  required=True,
30
30
  clearable=False,
31
- default=current_financial_month,
31
+ initial=current_financial_month,
32
32
  )
33
33
 
34
34
  performance_by = wb_filters.ChoiceFilter(
35
35
  label="Performance By",
36
36
  choices=PerformanceBy.choices,
37
- default=PerformanceBy.PRICE.name,
37
+ initial=PerformanceBy.PRICE.name,
38
38
  method="fake_filter",
39
39
  clearable=False,
40
40
  required=True,
@@ -91,7 +91,7 @@ class PerformancePandasFilter(PandasFilterSetMixin, BaseProductFilterSet):
91
91
 
92
92
 
93
93
  class ProductPerformanceNetNewMoneyFilter(PandasFilterSetMixin, BaseProductFilterSet):
94
- is_active = wb_filters.BooleanFilter(label="Is Active", method="filter_active_products", default=True)
94
+ is_active = wb_filters.BooleanFilter(label="Is Active", method="filter_active_products", initial=True)
95
95
  net_negative_money__gte = wb_filters.NumberFilter(
96
96
  label="Net Negative money", lookup_expr="gte", field_name="net_negative_money"
97
97
  )
@@ -126,7 +126,7 @@ class ProductPerformanceNetNewMoneyFilter(PandasFilterSetMixin, BaseProductFilte
126
126
  method=lambda queryset, label, value: queryset,
127
127
  required=True,
128
128
  clearable=False,
129
- default=last_period_date_range,
129
+ initial=last_period_date_range,
130
130
  )
131
131
 
132
132
  def filter_active_products(self, queryset, name, value):
@@ -164,7 +164,7 @@ class PerformanceComparisonFilter(PandasFilterSetMixin, BaseProductFilterSet):
164
164
  method="fake_filter",
165
165
  )
166
166
  compare_primary_benchmark = wb_filters.BooleanFilter(
167
- default=False, label="Compare against primary benchmark", method="fake_filter"
167
+ initial=False, label="Compare against primary benchmark", method="fake_filter"
168
168
  )
169
169
 
170
170
  class Meta:
@@ -6,7 +6,7 @@ from wbportfolio.models import Portfolio
6
6
 
7
7
 
8
8
  class PortfolioFilterSet(wb_filters.FilterSet):
9
- is_tracked = wb_filters.BooleanFilter(default=True, label="Is tracked")
9
+ is_tracked = wb_filters.BooleanFilter(initial=True, label="Is tracked")
10
10
  instrument = wb_filters.ModelChoiceFilter(
11
11
  label="Instrument",
12
12
  queryset=Instrument.objects.all(),
@@ -37,7 +37,7 @@ class PortfolioFilterSet(wb_filters.FilterSet):
37
37
 
38
38
 
39
39
  class PortfolioTreeGraphChartFilterSet(wb_filters.FilterSet):
40
- date = wb_filters.DateFilter(method="fake_filter", default=get_latest_asset_position, required=True)
40
+ date = wb_filters.DateFilter(method="fake_filter", initial=get_latest_asset_position, required=True)
41
41
 
42
42
  class Meta:
43
43
  model = Portfolio
@@ -80,20 +80,20 @@ class AssetPositionPandasFilter(DateFilterMixin, PandasFilterSetMixin, wb_filter
80
80
  label="Date Range",
81
81
  required=True,
82
82
  clearable=False,
83
- default=current_financial_month,
83
+ initial=current_financial_month,
84
84
  )
85
85
 
86
86
  group_by = wb_filters.ChoiceFilter(
87
87
  label="Group By",
88
88
  choices=GroupbyChoice.choices,
89
- default=GroupbyChoice.UNDERLYING_INSTRUMENT,
89
+ initial=GroupbyChoice.UNDERLYING_INSTRUMENT,
90
90
  method="fake_filter",
91
91
  clearable=False,
92
92
  required=True,
93
93
  )
94
94
 
95
95
  groupby_classification_height = wb_filters.NumberFilter(
96
- method="fake_filter", label="Classification Height (groupby)", default=0, clearable=False, required=True
96
+ method="fake_filter", label="Classification Height (groupby)", initial=0, clearable=False, required=True
97
97
  )
98
98
 
99
99
  class Meta:
@@ -168,17 +168,17 @@ class AggregatedAssetPositionLiquidityFilter(PandasFilterSetMixin, wb_filters.Fi
168
168
  historic_date = wb_filters.DateFilter(
169
169
  label="Historic Date",
170
170
  method=lambda queryset, label, value: queryset,
171
- default=get_latest_date_based_on_multiple_models,
171
+ initial=get_latest_date_based_on_multiple_models,
172
172
  required=True,
173
173
  )
174
174
  compared_date = wb_filters.DateFilter(
175
175
  label="Compared Date",
176
176
  method=lambda queryset, label, value: queryset,
177
- default=get_latest_end_quarter_date_asset_position,
177
+ initial=get_latest_end_quarter_date_asset_position,
178
178
  required=True,
179
179
  )
180
180
  bigger_than_x = wb_filters.NumberFilter(
181
- label="Bigger Than..", method=lambda queryset, label, value: queryset, default=1.00, required=True, precision=2
181
+ label="Bigger Than..", method=lambda queryset, label, value: queryset, initial=1.00, required=True, precision=2
182
182
  )
183
183
 
184
184
  class Meta:
@@ -42,7 +42,7 @@ class BaseProductFilterSet(InstrumentFilterSet):
42
42
  label_key=ProductGroup.get_representation_label_key(),
43
43
  )
44
44
  is_invested = wb_filters.BooleanFilter(label="Invested")
45
- is_active = wb_filters.BooleanFilter(label="Only Active", method="filter_is_active", default=True)
45
+ is_active = wb_filters.BooleanFilter(label="Only Active", method="filter_is_active", initial=True)
46
46
 
47
47
  class Meta:
48
48
  model = Product
@@ -141,7 +141,7 @@ class ProductFeeFilter(BaseProductFilterSet):
141
141
  method=lambda queryset, label, value: queryset,
142
142
  required=True,
143
143
  clearable=False,
144
- default=last_period_date_range(),
144
+ initial=last_period_date_range(),
145
145
  )
146
146
 
147
147
  def filter_active_products(self, queryset, name, value):
@@ -6,7 +6,7 @@ from wbportfolio.models import PortfolioRole
6
6
 
7
7
 
8
8
  class PortfolioRoleFilterSet(wb_filters.FilterSet):
9
- is_active = wb_filters.BooleanFilter(method="filter_is_active", default=True, label="Is Active")
9
+ is_active = wb_filters.BooleanFilter(method="filter_is_active", initial=True, label="Is Active")
10
10
 
11
11
  def filter_is_active(self, queryset, name, value):
12
12
  if value is True:
@@ -68,6 +68,6 @@ def add_classification_instrument_filter(sender, request=None, *args, **kwargs):
68
68
 
69
69
  return {
70
70
  "only_invested": wb_filters.BooleanFilter(
71
- method=_filter_invested, label="Invested Instruments (last date)", default=False
71
+ method=_filter_invested, label="Invested Instruments (last date)", initial=False
72
72
  )
73
73
  }
@@ -231,7 +231,7 @@ class ClaimGroupByFilter(CommissionBaseFilterSet):
231
231
  group_by = wb_filters.ChoiceFilter(
232
232
  label="Group By",
233
233
  choices=ClaimGroupbyChoice.choices(),
234
- default=ClaimGroupbyChoice.PRODUCT.name,
234
+ initial=ClaimGroupbyChoice.PRODUCT.name,
235
235
  method=lambda queryset, label, value: queryset,
236
236
  required=True,
237
237
  clearable=False,
@@ -242,11 +242,11 @@ class ClaimGroupByFilter(CommissionBaseFilterSet):
242
242
  method=lambda queryset, label, value: queryset,
243
243
  required=True,
244
244
  clearable=False,
245
- default=year_to_date_range,
245
+ initial=year_to_date_range,
246
246
  )
247
247
 
248
248
  groupby_classification_group = wb_filters.ModelChoiceFilter(
249
- default=lambda k, v, f: get_default_classification_group().id,
249
+ initial=lambda k, v, f: get_default_classification_group().id,
250
250
  method=lambda queryset, label, value: queryset,
251
251
  label="Group by Classification Group",
252
252
  queryset=ClassificationGroup.objects.all(),
@@ -324,7 +324,8 @@ class ConsolidatedTradeSummaryTableFilterSet(PandasFilterSetMixin, ClaimGroupByF
324
324
  class DistributionNNMChartFilter(ClaimGroupByFilter):
325
325
  percent = wb_filters.BooleanFilter(
326
326
  method="fake_filter",
327
- default=False,
327
+ initial=False,
328
+ required=True,
328
329
  help_text="True if the value are displayed in percentage of the initial total AUM",
329
330
  label="Show percentage",
330
331
  )
@@ -338,10 +339,10 @@ class CumulativeNNMChartFilter(ClaimGroupByFilter):
338
339
  groupby_classification_group = group_by = None
339
340
 
340
341
  hide_projected_monthly_nnm_target = wb_filters.BooleanFilter(
341
- default=True, label="Hide Target line", method=lambda queryset, label, value: queryset
342
+ initial=True, required=True, label="Hide Target line", method=lambda queryset, label, value: queryset
342
343
  )
343
344
  projected_monthly_nnm_target = wb_filters.NumberFilter(
344
- default=lambda k, v, f: get_monthly_nnm_target(),
345
+ initial=lambda k, v, f: get_monthly_nnm_target(),
345
346
  method=lambda queryset, label, value: queryset,
346
347
  label="Projected Monthly NNM Target",
347
348
  )
@@ -369,7 +370,7 @@ class ProfitAndLossPandasFilter(PandasFilterSetMixin, ClaimFilter):
369
370
  method=lambda queryset, label, value: queryset,
370
371
  required=True,
371
372
  clearable=False,
372
- default=current_financial_quarter,
373
+ initial=current_financial_quarter,
373
374
  )
374
375
 
375
376
  class Meta:
@@ -426,7 +427,7 @@ class NegativeTermimalAccountPerProductFilterSet(wb_filters.FilterSet):
426
427
  sum_shares__lte = wb_filters.NumberFilter(lookup_expr="lte", field_name="sum_shares", label="Total Shares")
427
428
 
428
429
  only_approved = wb_filters.BooleanFilter(
429
- default=False, label="Only Approved claims", method="filter_only_approve_claims"
430
+ initial=False, label="Only Approved claims", method="filter_only_approve_claims"
430
431
  )
431
432
 
432
433
  def filter_only_approve_claims(self, queryset, name, value):
@@ -18,7 +18,8 @@ class FeesFilter(TransactionFilterSet):
18
18
  fee_date = wb_filters.DateRangeFilter(
19
19
  method=wb_filters.DateRangeFilter.base_date_range_filter_method,
20
20
  label="Date Range",
21
- default=get_transaction_default_date_range,
21
+ initial=get_transaction_default_date_range,
22
+ required=True,
22
23
  )
23
24
  total_value_usd__gte = total_value_usd__lte = transaction_underlying_type = transaction_date = None
24
25
 
@@ -59,7 +60,7 @@ class FeesAggregatedFilter(PandasFilterSetMixin, wb_filters.FilterSet):
59
60
  method=wb_filters.DateRangeFilter.base_date_range_filter_method,
60
61
  required=True,
61
62
  clearable=False,
62
- default=current_quarter_date_range,
63
+ initial=current_quarter_date_range,
63
64
  )
64
65
 
65
66
  class Meta:
@@ -71,7 +71,7 @@ class TradeFilter(OppositeSharesFieldMethodMixin, TransactionFilterSet):
71
71
  # )
72
72
  total_value_usd__gte = total_value_usd__lte = transaction_underlying_type = None
73
73
  marked_for_deletion = wb_filters.BooleanFilter(
74
- label="Marked For Deletion", default=False, field_name="marked_for_deletion", lookup_expr="exact"
74
+ label="Marked For Deletion", initial=False, field_name="marked_for_deletion", lookup_expr="exact"
75
75
  )
76
76
  pivot_date = wb_filters.DateFilter(hidden=True, method="filter_pivot_date")
77
77
 
@@ -47,7 +47,7 @@ class TransactionFilterSet(wb_filters.FilterSet):
47
47
  transaction_date = wb_filters.DateRangeFilter(
48
48
  method=wb_filters.DateRangeFilter.base_date_range_filter_method,
49
49
  label="Date Range",
50
- default=get_transaction_default_date_range,
50
+ initial=get_transaction_default_date_range,
51
51
  )
52
52
 
53
53
  portfolio = wb_filters.ModelChoiceFilter(
@@ -94,6 +94,6 @@ class TransactionPortfolioFilterSet(TransactionFilterSet):
94
94
  label="Transaction Date",
95
95
  lookup_expr="exact",
96
96
  field_name="transaction_date",
97
- default=get_transaction_lte_default,
97
+ initial=get_transaction_lte_default,
98
98
  required=True,
99
99
  )
@@ -1,5 +1,3 @@
1
- from contextlib import suppress
2
-
3
1
  from django.db import models
4
2
  from django.db.models.signals import post_save
5
3
  from django.dispatch import receiver
@@ -58,6 +56,7 @@ class AccountReconciliation(Reconciliation):
58
56
  "Account Reconciliation Events",
59
57
  "A notification that informs the user about an account reconciliation event.",
60
58
  email=True,
59
+ is_lock=True,
61
60
  ),
62
61
  ]
63
62
 
@@ -80,12 +79,13 @@ class AccountReconciliation(Reconciliation):
80
79
  def get_representation_label_key(cls):
81
80
  return "{{account}} {{reconciliation_date}}"
82
81
 
83
- def notify(self, update: bool = False):
82
+ def notify(self, update: bool = False, silent_errors: bool = True) -> None:
84
83
  registry = global_preferences_registry.manager()
85
84
  title = registry["wbportfolio__account_holding_reconciliation_notification_title"]
86
85
  body = registry[f"wbportfolio__account_holding_reconciliation_notification_body{'_update' if update else ''}"]
86
+ errors_entries = []
87
87
  for role in self.account.roles.filter(role_type__key="reconciliation-manager"):
88
- with suppress(User.DoesNotExist):
88
+ try:
89
89
  user = User.objects.get(profile_id=role.entry.id)
90
90
  send_notification(
91
91
  code="wbportfolio.account_reconciliation.notify",
@@ -95,6 +95,12 @@ class AccountReconciliation(Reconciliation):
95
95
  reverse_name="wbportfolio:accountreconciliation-detail",
96
96
  reverse_args=[self.id],
97
97
  )
98
+ except User.DoesNotExist:
99
+ errors_entries.append(role.entry)
100
+ if errors_entries and not silent_errors:
101
+ raise ValueError(
102
+ f"Because of missing valid user account, we couldn't successfully notify the account holding reconciliation to the following customers: {', '.join(errors_entries)}. Note: The other customers were successfully notified."
103
+ )
98
104
 
99
105
 
100
106
  @receiver(post_save, sender=AccountReconciliation)
@@ -356,11 +356,19 @@ class ContributorPortfolioChartView(UserPortfolioRequestPermissionMixin, viewset
356
356
  title_config_class = ContributorPortfolioChartTitleConfig
357
357
  endpoint_config_class = ContributorPortfolioChartEndpointConfig
358
358
 
359
+ ROW_HEIGHT: int = 20
360
+
361
+ @property
362
+ def min_height(self):
363
+ if hasattr(self, "nb_rows"):
364
+ return self.nb_rows * self.ROW_HEIGHT
365
+ return "300px"
366
+
359
367
  @cached_property
360
368
  def hedged_currency(self) -> Currency | None:
361
369
  if "hedged_currency" in self.request.GET:
362
370
  with suppress(Currency.DoesNotExist):
363
- return Currency.objects.get(pk=self.kwargs["hedged_currency"])
371
+ return Currency.objects.get(pk=self.request.GET["hedged_currency"])
364
372
 
365
373
  @cached_property
366
374
  def show_lookthrough(self) -> bool:
@@ -407,6 +415,7 @@ class ContributorPortfolioChartView(UserPortfolioRequestPermissionMixin, viewset
407
415
 
408
416
  text_forex = df_forex.contribution_forex.apply(lambda x: f"{x:,.2%}")
409
417
  text_equity = contribution_equity.apply(lambda x: f"{x:,.2%}")
418
+ setattr(self, "nb_rows", df.shape[0])
410
419
  fig.add_trace(
411
420
  go.Bar(
412
421
  y=df.instrument_id,
@@ -443,10 +452,16 @@ class ContributorPortfolioChartView(UserPortfolioRequestPermissionMixin, viewset
443
452
  paper_bgcolor="rgba(0,0,0,0)",
444
453
  plot_bgcolor="rgba(0,0,0,0)",
445
454
  font=dict(family="roboto", size=12, color="black"),
455
+ bargap=0.3,
446
456
  )
447
457
  # fig = get_horizontal_barplot(df, x_label="contribution_total", y_label="name")
448
458
  return fig
449
459
 
460
+ def parse_figure_dict(self, figure_dict: dict[str, any]) -> dict[str, any]:
461
+ figure_dict = super().parse_figure_dict(figure_dict)
462
+ figure_dict["style"]["minHeight"] = self.min_height
463
+ return figure_dict
464
+
450
465
  def get_queryset(self):
451
466
  if self.has_portfolio_access:
452
467
  return super().get_queryset().filter(portfolio=self.portfolio)
@@ -46,7 +46,13 @@ class AccountReconciliationModelViewSet(viewsets.ModelViewSet):
46
46
  button_config_class = AccountReconciliationButtonViewConfig
47
47
  endpoint_config_class = AccountReconciliationEndpointViewConfig
48
48
 
49
- filterset_fields = {"account": ["exact"]}
49
+ filterset_fields = {
50
+ "account": ["exact"],
51
+ "creator": ["exact"],
52
+ "approved_by": ["exact"],
53
+ "reconciliation_date": ["gte", "exact", "lte"],
54
+ "approved_dt": ["gte", "lte"],
55
+ }
50
56
  ordering = ordering_fields = ["-reconciliation_date"]
51
57
 
52
58
  def get_queryset(self):
@@ -108,8 +114,11 @@ class AccountReconciliationModelViewSet(viewsets.ModelViewSet):
108
114
 
109
115
  @action(methods=["PATCH"], detail=True)
110
116
  def notify(self, request: "Request", pk: int | None = None) -> Response:
111
- self.get_object().notify(update=True)
112
- return Response()
117
+ try:
118
+ self.get_object().notify(update=True, silent_errors=False)
119
+ return Response()
120
+ except ValueError as e:
121
+ return Response(str(e), status=status.HTTP_400_BAD_REQUEST)
113
122
 
114
123
 
115
124
  class AccountReconciliationLineModelViewSet(viewsets.ModelViewSet):
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: wbportfolio
3
- Version: 1.50.9
3
+ Version: 1.50.11
4
4
  Author-email: Christopher Wittlinger <c.wittlinger@stainly.com>
5
5
  License-File: LICENSE
6
6
  Requires-Dist: cryptography==3.4.*
@@ -75,22 +75,22 @@ wbportfolio/factories/transactions.py,sha256=jZqTNRpW344DSYjV5tAqU5y30Kc7GRGbZ3B
75
75
  wbportfolio/fdm/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
76
76
  wbportfolio/fdm/tasks.py,sha256=59hXt3TOJaM8KpUaKdBNAGsO7NFMHaAlNA0T3FTUau0,533
77
77
  wbportfolio/filters/__init__.py,sha256=m44CdyYMtku8rMGyiX8KSmMdvyqaElKW4UMkEqOC1VM,1374
78
- wbportfolio/filters/assets.py,sha256=gpCwxlje1mY9IGlxfvQyNgyE5RcT-r3B2tI14hB92X4,18114
79
- wbportfolio/filters/assets_and_net_new_money_progression.py,sha256=dgI3WWlfYjaDg15-C4Sh2HQoY0kQh9mQUWxn4SAPLnM,1403
78
+ wbportfolio/filters/assets.py,sha256=Tbci0xXuFzs2wCSMauhc-LsnB5LdmxcPVFk3AavM5z8,18158
79
+ wbportfolio/filters/assets_and_net_new_money_progression.py,sha256=IYl_qMFO9QKhXhCTtz2JrOjlAKdEkykNlu4DO_H7HkQ,1403
80
80
  wbportfolio/filters/custodians.py,sha256=pStQgPQPhPpnt57_V7BuXbFXmRiZBEAiEeMFuQmt2NE,287
81
- wbportfolio/filters/esg.py,sha256=sQ5HwiUlhfKeFqJ2O5koXyTscpN21UKRUSi8d90jSlI,688
82
- wbportfolio/filters/performances.py,sha256=fAMb8HkWSmBl1xg5P4MZ8WJsV5x7uCcBf7ETHdfXjkI,7325
83
- wbportfolio/filters/portfolios.py,sha256=IqkDj3POQ1MHGZO9k7TNuhf5fZ_yR9vPPcMFELkQsnQ,1469
84
- wbportfolio/filters/positions.py,sha256=ERdcTCNw7peGstKSl3W5t1wlSUM8a3anoesoycohF98,8548
85
- wbportfolio/filters/products.py,sha256=_QFL3I132q-3JUDji_Wh2Qkv45DKnQrR3N8_luGK0K0,6492
86
- wbportfolio/filters/roles.py,sha256=-0tOl-WJDqwXAfcJePpkjQfZB9o13I99euem5XGpMjk,920
87
- wbportfolio/filters/signals.py,sha256=3GrsxPwZg-6bvvZ222VfF212yNTJYQP4n5hWIEnTtpA,3144
81
+ wbportfolio/filters/esg.py,sha256=ZEUQh3IQxLSshVrgtPqHC_ToirrllkCXR_KzUlCUtkA,688
82
+ wbportfolio/filters/performances.py,sha256=xJC7fe8XNPz159cewMD8Es8u89vzgpZT4D2Gm1YToM8,7340
83
+ wbportfolio/filters/portfolios.py,sha256=o5S5FaUnHTmtgpBPzEom7odypdyM_I2O6Lbhj7Oy4nU,1469
84
+ wbportfolio/filters/positions.py,sha256=7eMqwqnNd_owi2Mg-1Uf9K9K9SHSgdZ8CcYgWw49qgI,8548
85
+ wbportfolio/filters/products.py,sha256=jOoRKDm_2n2a-Y1dHWl1zjdrwy4Cek57Qa3Q10p_zzY,6492
86
+ wbportfolio/filters/roles.py,sha256=jb8WLzZ_e03x8XkAWuYAdPgMyre3h-rtgYXKJ3dqkhw,920
87
+ wbportfolio/filters/signals.py,sha256=XZ1d50yas47Xy57ZfmvCVjMSKojaoqrc5FHJBcVadtk,3144
88
88
  wbportfolio/filters/transactions/__init__.py,sha256=WHAwqZLRTAS46lLscGJYtKYWyEknsY5MqeSD0ue1r-o,662
89
- wbportfolio/filters/transactions/claim.py,sha256=GqWSFNro_bmUwVOLhsQEjV1kGHzQ_1iJBvmSRoCWCU8,17913
90
- wbportfolio/filters/transactions/fees.py,sha256=4EDmwgianx0iIIaIx7XgEjRDPI9nqBUq1zL1FpdtYAg,2134
89
+ wbportfolio/filters/transactions/claim.py,sha256=eSykgNzcytMWWTmlGlaqBuh98vfOKoTLvA3cglc_jZ0,17951
90
+ wbportfolio/filters/transactions/fees.py,sha256=Oawed5qlhKTFbuq0inzz2vkjtEgLObnF--m-k4HC0G4,2157
91
91
  wbportfolio/filters/transactions/mixins.py,sha256=TEV3MUsiQTeu4NdFYHMIIMonmC7CdFF80JTpWYIvfRQ,550
92
- wbportfolio/filters/transactions/trades.py,sha256=wq39DQwKpSioNwcQkHQ8ydDklZRPonUiXUH7NzTJCEs,9778
93
- wbportfolio/filters/transactions/transactions.py,sha256=TQNusdKIit_JKWFRVk3JERmHd4YvxLq-NiyEShJ_eDI,3538
92
+ wbportfolio/filters/transactions/trades.py,sha256=fJ_JjjgBjJd9US0MdjksscCDNIbcLTrWUTT8Nt4kVY4,9778
93
+ wbportfolio/filters/transactions/transactions.py,sha256=7rMpP3V1c0NuJyji-aJq76WPurLZpS9PGI8FgjB4a0A,3538
94
94
  wbportfolio/fixtures/product_factsheets.yaml,sha256=z5o-viDbgwWkssDJXZYayasFgw1nJ0uiOiYrJNDkRtg,5455
95
95
  wbportfolio/fixtures/wbportfolio.yaml.gz,sha256=902nxQZM6VcVcc0wI9AYaSedcJIfsK5letLF31j1Jdg,1479453
96
96
  wbportfolio/fixtures/wbrisk_management.yaml.gz,sha256=alFDRu8S9R6IsaIkpJe_v36B2GvHgHeNJVumUB5m_NQ,155413
@@ -269,7 +269,7 @@ wbportfolio/models/mixins/instruments.py,sha256=SgBreTpa_X3uyCWo7t8B0VaTtl49IjmB
269
269
  wbportfolio/models/mixins/liquidity_stress_test.py,sha256=whkzjtbOyl_ncNyaQBORb_Z_rDgcvfdTYPgqPolu7dA,58865
270
270
  wbportfolio/models/reconciliations/__init__.py,sha256=MXH5fZIPGDRBgJkO6wVu_NLRs8fkP1im7G6d-h36lQY,127
271
271
  wbportfolio/models/reconciliations/account_reconciliation_lines.py,sha256=QP6M7hMcyFbuXBa55Y-azui6Dl_WgbzMntEqWzQkbfM,7394
272
- wbportfolio/models/reconciliations/account_reconciliations.py,sha256=_teOTNePxua9C894auy8CvdOFsmUnQiOM2_TZAHvzY4,3955
272
+ wbportfolio/models/reconciliations/account_reconciliations.py,sha256=rofSxetFfEJov6mPyoTvGxELA16HILyJZtQvm_kwYU0,4405
273
273
  wbportfolio/models/reconciliations/reconciliations.py,sha256=kF-BNhUoT4TCn1RIgPSkdEk1iX4NQeZlGGFd_ZulAZU,686
274
274
  wbportfolio/models/transactions/__init__.py,sha256=R-4fHylrUf3773kGSEt09vtYj3LUlia5yf7rxHXjvHA,295
275
275
  wbportfolio/models/transactions/claim.py,sha256=XUSephKt-VkILe2i-Sd9aoVxB-50PJANCPIDLa_dKl4,25872
@@ -401,7 +401,7 @@ wbportfolio/tests/viewsets/transactions/__init__.py,sha256=47DEQpj8HBSa-_TImW-5J
401
401
  wbportfolio/tests/viewsets/transactions/test_claims.py,sha256=QEZfMAW07dyoZ63t2umSwGOqvaTULfYfbN_F4ZoSAcw,6368
402
402
  wbportfolio/viewsets/__init__.py,sha256=3kUaQ66ybvROwejd3bEcSt4XKzfOlPDaeoStMvlz7qY,2294
403
403
  wbportfolio/viewsets/adjustments.py,sha256=5hWCjxSgUIsrPOmJKoDYK3gywdMTI0aYDorEj1FXRVc,1429
404
- wbportfolio/viewsets/assets.py,sha256=FgJhBK13tAkrDyTiWsgnIT0Oq39mlvJTQSq1ztopQhY,24172
404
+ wbportfolio/viewsets/assets.py,sha256=Gf5QKDM7QR9MC8GJhMNzaY7NzeKV_yOQw0wktKPEc9o,24661
405
405
  wbportfolio/viewsets/assets_and_net_new_money_progression.py,sha256=Jl4vEQP4N2OFL5IGBXoKcj-0qaPviU0I8npvQLw4Io0,4464
406
406
  wbportfolio/viewsets/custodians.py,sha256=CTFqkqVP1R3AV7lhdvcdICxB5DfwDYCyikNSI5kbYEo,2322
407
407
  wbportfolio/viewsets/esg.py,sha256=27MxxdXQH3Cq_1UEYmcrF7htUOg6i81fUpbVQXAAKJI,6985
@@ -415,7 +415,7 @@ wbportfolio/viewsets/positions.py,sha256=2rzFHB_SI09rXC_EYi58G_eqvzONbk8z61JDkkj
415
415
  wbportfolio/viewsets/product_groups.py,sha256=YvmuXPPy98K1J_rz6YPsx9gNK-tCS2P-wc1uRYgfyo0,2399
416
416
  wbportfolio/viewsets/product_performance.py,sha256=dRfRgifjGS1RgZSu9uJRM0SmB7eLnNUkPuqARMO4gyo,28371
417
417
  wbportfolio/viewsets/products.py,sha256=1KXUDXdNmBFYjQcvJkwUCnjIOKZT0cAk_XTihMKRWvw,20459
418
- wbportfolio/viewsets/reconciliations.py,sha256=nRWWfrMqZAXmXB1ZG3coUHjYEiZNblobO5u3zsXWono,7037
418
+ wbportfolio/viewsets/reconciliations.py,sha256=tRS7UBDtMn-07uA9QqYvnCtp_mZGVeULF2OJMfHJPZk,7357
419
419
  wbportfolio/viewsets/registers.py,sha256=eOuEhW2McHsOapCKue7M4eazrJnVpCBVxImpFccq0z0,2401
420
420
  wbportfolio/viewsets/roles.py,sha256=vnzS1mlJMZS3GObrss6SfXOr3KRb-OHB1s4Msvtn7xQ,1556
421
421
  wbportfolio/viewsets/signals.py,sha256=URxNz-7tKNBgvaFIE3FItfao3Md0dKQN_eVFwxxiErk,2125
@@ -522,7 +522,7 @@ wbportfolio/viewsets/transactions/rebalancing.py,sha256=6rIrdK0rtKL1afJ-tYfAGdQV
522
522
  wbportfolio/viewsets/transactions/trade_proposals.py,sha256=iQpC_Thbj56SmM05vPRsF1JZguGBDaTUH3I-_iCHCV0,5958
523
523
  wbportfolio/viewsets/transactions/trades.py,sha256=-yJ4j8NJTu2VWyhCq5BXGNND_925Ietoxx9k07SLVh0,21634
524
524
  wbportfolio/viewsets/transactions/transactions.py,sha256=ixDp-nsNA8t_A06rBCT19hOMJHy0iRmdz1XKdV1OwAs,4450
525
- wbportfolio-1.50.9.dist-info/METADATA,sha256=ykBmDv1llZ2irZi3thH6lVehwGjZPNVasF7jU4Z06_A,702
526
- wbportfolio-1.50.9.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
527
- wbportfolio-1.50.9.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
528
- wbportfolio-1.50.9.dist-info/RECORD,,
525
+ wbportfolio-1.50.11.dist-info/METADATA,sha256=-P0DH8eaypNkb_aIxSByI1N2TdeWYx9zZZXZ5QzGl84,703
526
+ wbportfolio-1.50.11.dist-info/WHEEL,sha256=tkmg4JIqwd9H8mL30xA7crRmoStyCtGp0VWshokd1Jc,105
527
+ wbportfolio-1.50.11.dist-info/licenses/LICENSE,sha256=jvfVH0SY8_YMHlsJHKe_OajiscQDz4lpTlqT6x24sVw,172
528
+ wbportfolio-1.50.11.dist-info/RECORD,,