Skip to content

Commit ccefe73

Browse files
change subscription filters to arrayfield (#707)
1 parent e4c2539 commit ccefe73

12 files changed

Lines changed: 165 additions & 205 deletions

backend/api/serializers/model_serializers.py

Lines changed: 21 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -6,9 +6,6 @@
66
from django.conf import settings
77
from django.db.models import Max, Min, Sum
88
from drf_spectacular.utils import extend_schema_serializer
9-
from rest_framework import serializers
10-
from rest_framework.exceptions import ValidationError
11-
129
from metering_billing.invoice import generate_balance_adjustment_invoice
1310
from metering_billing.models import (
1411
AddOnSpecification,
@@ -56,7 +53,6 @@
5653
)
5754
from metering_billing.utils import convert_to_date, now_utc
5855
from metering_billing.utils.enums import (
59-
CATEGORICAL_FILTER_OPERATORS,
6056
CUSTOMER_BALANCE_ADJUSTMENT_STATUS,
6157
FLAT_FEE_BEHAVIOR,
6258
INVOICE_STATUS_ENUM,
@@ -70,6 +66,8 @@
7066
USAGE_BEHAVIOR,
7167
USAGE_BILLING_BEHAVIOR,
7268
)
69+
from rest_framework import serializers
70+
from rest_framework.exceptions import ValidationError
7371

7472
SVIX_CONNECTOR = settings.SVIX_CONNECTOR
7573
logger = logging.getLogger("django.server")
@@ -199,36 +197,18 @@ class Meta:
199197
comparison_value = serializers.ListField(child=serializers.CharField())
200198

201199

202-
class SubscriptionCategoricalFilterSerializer(
203-
ConvertEmptyStringToNullMixin, TimezoneFieldMixin, serializers.ModelSerializer
200+
class SubscriptionFilterSerializer(
201+
ConvertEmptyStringToNullMixin, TimezoneFieldMixin, serializers.Serializer
204202
):
205-
class Meta:
206-
model = CategoricalFilter
207-
fields = ("value", "property_name")
208-
extra_kwargs = {
209-
"property_name": {
210-
"required": True,
211-
},
212-
"value": {"required": True},
213-
}
214-
215203
value = serializers.CharField()
216204
property_name = serializers.CharField(
217205
help_text="The string name of the property to filter on. Example: 'product_id'"
218206
)
219207

220-
def create(self, validated_data):
221-
comparison_value = validated_data.pop("value")
222-
comparison_value = [comparison_value]
223-
validated_data["comparison_value"] = comparison_value
224-
return CategoricalFilter.objects.get_or_create(
225-
**validated_data, operator=CATEGORICAL_FILTER_OPERATORS.ISIN
226-
)
227-
228208
def to_representation(self, instance):
229209
data = {
230-
"property_name": instance.property_name,
231-
"value": instance.comparison_value[0],
210+
"property_name": instance[0],
211+
"value": instance[1],
232212
}
233213
return data
234214

@@ -345,9 +325,7 @@ class Meta:
345325
}
346326

347327
subscription_id = SubscriptionUUIDField(source="subscription_record_id")
348-
subscription_filters = SubscriptionCategoricalFilterSerializer(
349-
many=True, source="filters"
350-
)
328+
subscription_filters = SubscriptionFilterSerializer(many=True)
351329
customer = LightweightCustomerSerializer()
352330
billing_plan = LightweightPlanVersionSerializer()
353331
addons = LightweightAddOnSubscriptionRecordSerializer(
@@ -445,11 +423,11 @@ def get_adjustments(self, obj) -> InvoiceLineItemAdjustmentSerializer(many=True)
445423

446424
def get_subscription_filters(
447425
self, obj
448-
) -> SubscriptionCategoricalFilterSerializer(many=True, allow_null=True):
426+
) -> SubscriptionFilterSerializer(many=True, allow_null=True):
449427
ass_sub_record = obj.associated_subscription_record
450428
if ass_sub_record:
451-
return SubscriptionCategoricalFilterSerializer(
452-
ass_sub_record.filters.all(), many=True
429+
return SubscriptionFilterSerializer(
430+
ass_sub_record.subscription_filters, many=True
453431
).data
454432
return None
455433

@@ -1640,7 +1618,7 @@ class Meta:
16401618
help_text="Whether the subscription automatically renews. Defaults to true.",
16411619
)
16421620
is_new = serializers.BooleanField(required=False)
1643-
subscription_filters = SubscriptionCategoricalFilterSerializer(
1621+
subscription_filters = SubscriptionFilterSerializer(
16441622
many=True,
16451623
required=False,
16461624
help_text="Add filter key, value pairs that define which events will be applied to this plan subscription.",
@@ -1683,22 +1661,9 @@ def create(self, validated_data):
16831661
filters = validated_data.pop("subscription_filters", [])
16841662
subscription_filters = []
16851663
for filter_data in filters:
1686-
sub_cat_filter_dict = {
1687-
"organization": validated_data["customer"].organization,
1688-
"property_name": filter_data["property_name"],
1689-
"operator": CATEGORICAL_FILTER_OPERATORS.ISIN,
1690-
"comparison_value": [filter_data["value"]],
1691-
}
1692-
try:
1693-
cf, _ = CategoricalFilter.objects.get_or_create(**sub_cat_filter_dict)
1694-
except CategoricalFilter.MultipleObjectsReturned:
1695-
cf = (
1696-
CategoricalFilter.objects.filter(**sub_cat_filter_dict)
1697-
.first()
1698-
.delete()
1699-
)
1700-
cf = CategoricalFilter.objects.filter(**sub_cat_filter_dict).first()
1701-
subscription_filters.append(cf)
1664+
subscription_filters.append(
1665+
[filter_data["property_name"], filter_data["value"]]
1666+
)
17021667
sr = SubscriptionRecord.create_subscription_record(
17031668
start_date=validated_data["start_date"],
17041669
end_date=validated_data.get("end_date"),
@@ -1759,7 +1724,7 @@ class Meta:
17591724
help_text="Whether the subscription automatically renews. Defaults to true.",
17601725
)
17611726
is_new = serializers.BooleanField(required=False)
1762-
subscription_filters = SubscriptionCategoricalFilterSerializer(
1727+
subscription_filters = SubscriptionFilterSerializer(
17631728
many=True,
17641729
required=False,
17651730
help_text="Add filter key, value pairs that define which events will be applied to this plan subscription.",
@@ -1825,22 +1790,9 @@ def create(self, validated_data):
18251790
filters = validated_data.pop("subscription_filters", [])
18261791
subscription_filters = []
18271792
for filter_data in filters:
1828-
sub_cat_filter_dict = {
1829-
"organization": validated_data["customer"].organization,
1830-
"property_name": filter_data["property_name"],
1831-
"operator": CATEGORICAL_FILTER_OPERATORS.ISIN,
1832-
"comparison_value": [filter_data["value"]],
1833-
}
1834-
try:
1835-
cf, _ = CategoricalFilter.objects.get_or_create(**sub_cat_filter_dict)
1836-
except CategoricalFilter.MultipleObjectsReturned:
1837-
cf = (
1838-
CategoricalFilter.objects.filter(**sub_cat_filter_dict)
1839-
.first()
1840-
.delete()
1841-
)
1842-
cf = CategoricalFilter.objects.filter(**sub_cat_filter_dict).first()
1843-
subscription_filters.append(cf)
1793+
subscription_filters.append(
1794+
[filter_data["property_name"], filter_data["value"]]
1795+
)
18441796
sr = SubscriptionRecord.create_subscription_record(
18451797
start_date=validated_data["start_date"],
18461798
end_date=validated_data.get("end_date"),
@@ -1869,9 +1821,7 @@ class Meta(SubscriptionRecordSerializer.Meta):
18691821
plan_detail = LightweightPlanVersionSerializer(
18701822
source="billing_plan", read_only=True
18711823
)
1872-
subscription_filters = SubscriptionCategoricalFilterSerializer(
1873-
source="filters", many=True, read_only=True
1874-
)
1824+
subscription_filters = SubscriptionFilterSerializer(many=True, read_only=True)
18751825

18761826

18771827
class SubscriptionInvoiceSerializer(SubscriptionRecordSerializer):
@@ -2137,7 +2087,7 @@ class SubscriptionRecordFilterSerializer(serializers.Serializer):
21372087
required=True,
21382088
help_text="Filter to a specific plan.",
21392089
)
2140-
subscription_filters = SubscriptionCategoricalFilterSerializer(
2090+
subscription_filters = SubscriptionFilterSerializer(
21412091
many=True,
21422092
required=False,
21432093
help_text="Filter to a specific set of subscription filters. If your billing model only allows for one subscription per customer, you very likely do not need this field. Must be formatted as a JSON-encoded + stringified list of dictionaries, where each dictionary has a key of 'property_name' and a key of 'value'.",
@@ -2222,7 +2172,7 @@ class AddOnSubscriptionRecordFilterSerializer(serializers.Serializer):
22222172
required=True,
22232173
help_text="Filter to a specific plan.",
22242174
)
2225-
attached_subscription_filters = SubscriptionCategoricalFilterSerializer(
2175+
attached_subscription_filters = SubscriptionFilterSerializer(
22262176
many=True,
22272177
required=False,
22282178
help_text="Filter to a specific set of subscription filters. If your billing model only allows for one subscription per customer, you very likely do not need this field. Must be formatted as a JSON-encoded + stringified list of dictionaries, where each dictionary has a key of 'property_name' and a key of 'value'.",

backend/api/serializers/nonmodel_serializers.py

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
LightweightCustomerSerializer,
44
LightweightMetricSerializer,
55
LightweightPlanVersionSerializer,
6-
SubscriptionCategoricalFilterSerializer,
6+
SubscriptionFilterSerializer,
77
)
88
from metering_billing.models import (
99
Customer,
@@ -70,9 +70,7 @@ class Meta:
7070
"plan": {"required": True, "read_only": True},
7171
}
7272

73-
subscription_filters = SubscriptionCategoricalFilterSerializer(
74-
many=True, source="filters"
75-
)
73+
subscription_filters = SubscriptionFilterSerializer(many=True)
7674
plan = LightweightPlanVersionSerializer(source="billing_plan")
7775

7876

@@ -120,7 +118,7 @@ class MetricAccessRequestSerializer(serializers.Serializer):
120118
queryset=Metric.objects.all(),
121119
help_text="The metric_id of the metric you want to check access for.",
122120
)
123-
subscription_filters = SubscriptionCategoricalFilterSerializer(
121+
subscription_filters = SubscriptionFilterSerializer(
124122
many=True,
125123
required=False,
126124
help_text="Used if you want to restrict the access check to only plans that fulfill certain subscription filter criteria. If your billing model does not have the ability multiple plans or subscriptions per customer, this is likely not relevant for you. ",
@@ -158,7 +156,7 @@ class FeatureAccessRequestSerializer(serializers.Serializer):
158156
queryset=Feature.objects.all(),
159157
help_text="The feature_id of the feature you want to check access for.",
160158
)
161-
subscription_filters = SubscriptionCategoricalFilterSerializer(
159+
subscription_filters = SubscriptionFilterSerializer(
162160
many=True,
163161
required=False,
164162
help_text="The subscription filters that are applied to this plan's relationship with the customer. If your billing model does not have the ability multiple plans or subscriptions per customer, this is likely not relevant for you. ",

0 commit comments

Comments
 (0)