Skip to content

Commit

Permalink
feat: create retired_at datetime field on policy models
Browse files Browse the repository at this point in the history
  • Loading branch information
zwidekalanga authored and iloveagent57 committed Jun 10, 2024
1 parent bf4b09a commit 9bcc9a6
Show file tree
Hide file tree
Showing 5 changed files with 80 additions and 12 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ class Meta:
'description',
'active',
'retired',
'retired_at',
'enterprise_customer_uuid',
'catalog_uuid',
'subsidy_uuid',
Expand Down Expand Up @@ -215,6 +216,7 @@ class Meta:
'description',
'active',
'retired',
'retired_at',
'enterprise_customer_uuid',
'catalog_uuid',
'subsidy_uuid',
Expand Down Expand Up @@ -427,6 +429,7 @@ class Meta:
'description',
'active',
'retired',
'retired_at',
'catalog_uuid',
'subsidy_uuid',
'access_method',
Expand Down Expand Up @@ -459,6 +462,10 @@ class Meta:
'allow_null': True,
'required': False,
},
'retired_at': {
'allow_null': True,
'required': False,
},
'catalog_uuid': {
'allow_null': False,
'required': False,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,7 @@ def setup_subsidy_mocks(self):
'id': 123455,
'active_datetime': self.yesterday,
'expiration_datetime': self.tomorrow,
'retired_at': None,
'current_balance': 4,
'is_active': True,
'starting_balance': 4,
Expand Down Expand Up @@ -286,6 +287,7 @@ def test_detail_view(self, role_context_dict):
'access_method': 'direct',
'active': True,
'retired': False,
'retired_at': None,
'catalog_uuid': str(self.redeemable_policy.catalog_uuid),
'display_name': self.redeemable_policy.display_name,
'description': 'A generic description',
Expand Down Expand Up @@ -365,7 +367,6 @@ def test_list_view(self, role_context_dict):
"""
# Set the JWT-based auth that we'll use for every request
self.set_jwt_cookie([role_context_dict])

# Test the retrieve endpoint
response = self.client.get(
reverse('api:v1:subsidy-access-policies-list'),
Expand All @@ -381,6 +382,7 @@ def test_list_view(self, role_context_dict):
'access_method': 'direct',
'active': True,
'retired': False,
'retired_at': None,
'catalog_uuid': str(self.non_redeemable_policy.catalog_uuid),
'display_name': self.non_redeemable_policy.display_name,
'description': 'A generic description',
Expand Down Expand Up @@ -411,6 +413,7 @@ def test_list_view(self, role_context_dict):
'access_method': 'direct',
'active': True,
'retired': False,
'retired_at': None,
'catalog_uuid': str(self.redeemable_policy.catalog_uuid),
'display_name': self.redeemable_policy.display_name,
'description': 'A generic description',
Expand Down Expand Up @@ -458,16 +461,19 @@ def test_list_view(self, role_context_dict):

# Assert that we only call the subsidy service to list transaction
# aggregates once per policy
self.mock_subsidy_client.list_subsidy_transactions.assert_has_calls([
call(
subsidy_uuid=self.redeemable_policy.subsidy_uuid,
subsidy_access_policy_uuid=self.redeemable_policy.uuid
),
call(
subsidy_uuid=self.non_redeemable_policy.subsidy_uuid,
subsidy_access_policy_uuid=self.non_redeemable_policy.uuid,
),
])
self.mock_subsidy_client.list_subsidy_transactions.assert_has_calls(
[
call(
subsidy_uuid=self.redeemable_policy.subsidy_uuid,
subsidy_access_policy_uuid=self.redeemable_policy.uuid
),
call(
subsidy_uuid=self.non_redeemable_policy.subsidy_uuid,
subsidy_access_policy_uuid=self.non_redeemable_policy.uuid,
),
],
any_order=True
)

@ddt.data(
{
Expand Down Expand Up @@ -508,6 +514,7 @@ def test_destroy_view(self, request_payload, expected_change_reason):
'access_method': 'direct',
'active': False,
'retired': False,
'retired_at': None,
'catalog_uuid': str(self.redeemable_policy.catalog_uuid),
'display_name': self.redeemable_policy.display_name,
'description': 'A generic description',
Expand Down Expand Up @@ -620,6 +627,7 @@ def test_update_views(self, is_patch, request_payload):
'access_method': policy_for_edit.access_method,
'active': policy_for_edit.active,
'retired': policy_for_edit.retired,
'retired_at': policy_for_edit.retired_at,
'catalog_uuid': str(policy_for_edit.catalog_uuid),
'display_name': policy_for_edit.display_name,
'description': policy_for_edit.description,
Expand Down Expand Up @@ -648,6 +656,13 @@ def test_update_views(self, is_patch, request_payload):
'group_associations': [],
'is_late_redemption_allowed': False,
}

if 'retired' in request_payload:
if request_payload['retired']:
expected_response['retired_at'] = response.json().get('retired_at')
else:
expected_response['retired_at'] = None

expected_response.update(request_payload)
self.assertEqual(expected_response, response.json())

Expand Down Expand Up @@ -883,6 +898,7 @@ def test_create_view(self, policy_type, extra_fields, expected_response_code, ex
'description': 'test description',
'active': True,
'retired': False,
'retired_at': None,
'enterprise_customer_uuid': str(TEST_ENTERPRISE_UUID),
'catalog_uuid': str(uuid4()),
'subsidy_uuid': str(uuid4()),
Expand Down Expand Up @@ -942,6 +958,7 @@ def test_idempotent_create_view(self, policy_type, extra_fields, expected_respon
'description': 'test description',
'active': True,
'retired': False,
'retired_at': None,
'enterprise_customer_uuid': enterprise_customer_uuid,
'catalog_uuid': catalog_uuid,
'subsidy_uuid': subsidy_uuid,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,7 @@ class PerLearnerEnrollmentCreditAccessPolicy(DjangoQLSearchMixin, BaseSubsidyAcc
'description',
'active',
'retired',
'retired_at',
'catalog_uuid',
'subsidy_uuid',
'late_redemption_allowed_until',
Expand Down Expand Up @@ -245,6 +246,7 @@ class PerLearnerSpendCreditAccessPolicy(DjangoQLSearchMixin, BaseSubsidyAccessPo
'description',
'active',
'retired',
'retired_at',
'catalog_uuid',
'subsidy_uuid',
'late_redemption_allowed_until',
Expand Down Expand Up @@ -303,6 +305,7 @@ class LearnerContentAssignmentAccessPolicy(DjangoQLSearchMixin, BaseSubsidyAcces
'description',
'active',
'retired',
'retired_at',
'catalog_uuid',
'subsidy_uuid',
'late_redemption_allowed_until',
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
# Generated by Django 4.2.13 on 2024-06-10 13:19

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('subsidy_access_policy', '0026_forced_redemption_tx_blank_not_editable'),
]

operations = [
migrations.AddField(
model_name='historicalsubsidyaccesspolicy',
name='retired_at',
field=models.DateTimeField(blank=True, help_text='The date and time when this Subsidy is considered retired.', null=True),
),
migrations.AddField(
model_name='subsidyaccesspolicy',
name='retired_at',
field=models.DateTimeField(blank=True, help_text='The date and time when this Subsidy is considered retired.', null=True),
),
]
20 changes: 19 additions & 1 deletion enterprise_access/apps/subsidy_access_policy/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

import requests
from django.conf import settings
from django.utils import timezone
from django.core.cache import cache as django_cache
from django.core.exceptions import ValidationError
from django.db import models
Expand Down Expand Up @@ -83,7 +84,7 @@ class SubsidyAccessPolicy(TimeStampedModel):
Tie together information used to control access to a subsidy.
This model joins group, catalog, and access method.
.. no_pii: This model has no PII
. no_pii: This model has no PII
"""

class Meta:
Expand Down Expand Up @@ -160,6 +161,13 @@ class Meta:
"(useful when you want to just expire a policy without expiring the whole plan)."
),
)
retired_at = models.DateTimeField(
null=True,
blank=True,
help_text=(
"The date and time when this Subsidy is considered retired."
)
)
catalog_uuid = models.UUIDField(
db_index=True,
help_text='The primary identifier of the catalog associated with this policy.',
Expand Down Expand Up @@ -222,6 +230,11 @@ class Meta:
),
)

def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Store the initial value of retired
self._original_retired = self.retired

# Customized version of HistoricalRecords to enable history tracking on child proxy models. See
# ProxyAwareHistoricalRecords docstring for more info.
history = ProxyAwareHistoricalRecords(inherit=True)
Expand Down Expand Up @@ -354,6 +367,11 @@ def save(self, *args, **kwargs):
# because it is not a concrete policy
raise TypeError("Can not create object of class SubsidyAccessPolicy")

# Update retired_at based on changes to retired
if self.retired != self._original_retired:
self.retired_at = timezone.now() if self.retired else None
self._original_retired = self.retired

self.policy_type = type(self).__name__
self.full_clean()
super().save(*args, **kwargs)
Expand Down

0 comments on commit 9bcc9a6

Please sign in to comment.