From 4b458099cf515e92c0b3692942a0b338fc52e455 Mon Sep 17 00:00:00 2001 From: Zainab Amir <zainab.amir@arbisoft.com> Date: Mon, 3 Feb 2020 13:21:44 +0500 Subject: [PATCH] Add unique_together to CourseEntitlement (#22948) Add unique_together on course_uuid and order_number to avoid duplicate records PROD-1064 --- .../entitlements/api/v1/tests/test_views.py | 53 +++++++++++++++++++ .../0015_add_unique_together_constraint.py | 29 ++++++++++ common/djangoapps/entitlements/models.py | 5 +- 3 files changed, 86 insertions(+), 1 deletion(-) create mode 100644 common/djangoapps/entitlements/migrations/0015_add_unique_together_constraint.py diff --git a/common/djangoapps/entitlements/api/v1/tests/test_views.py b/common/djangoapps/entitlements/api/v1/tests/test_views.py index 2006b9f520e..3428ce72ebf 100644 --- a/common/djangoapps/entitlements/api/v1/tests/test_views.py +++ b/common/djangoapps/entitlements/api/v1/tests/test_views.py @@ -141,6 +141,59 @@ class EntitlementViewSetTest(ModuleStoreTestCase): ) assert results == CourseEntitlementSerializer(course_entitlement).data + def test_add_duplicate_entitlement(self): + """ + Request with identical course_uuid and order_number should not create duplicate + entitlement + """ + course_uuid = uuid.uuid4() + entitlement_data = self._get_data_set(self.user, str(course_uuid)) + + response = self.client.post( + self.entitlements_list_url, + data=json.dumps(entitlement_data), + content_type='application/json', + ) + assert response.status_code == 201 + response = self.client.post( + self.entitlements_list_url, + data=json.dumps(entitlement_data), + content_type='application/json', + ) + assert response.status_code == 400 + course_entitlement = CourseEntitlement.objects.filter( + course_uuid=course_uuid, + order_number=entitlement_data['order_number'] + ) + assert course_entitlement.count() == 1 + + def test_order_number_null(self): + """ + Test that for same course_uuid order_number set to null is treated as unique + entitlement + """ + course_uuid = uuid.uuid4() + entitlement_data = self._get_data_set(self.user, str(course_uuid)) + entitlement_data['order_number'] = None + + response = self.client.post( + self.entitlements_list_url, + data=json.dumps(entitlement_data), + content_type='application/json', + ) + assert response.status_code == 201 + response = self.client.post( + self.entitlements_list_url, + data=json.dumps(entitlement_data), + content_type='application/json', + ) + assert response.status_code == 201 + course_entitlement = CourseEntitlement.objects.filter( + course_uuid=course_uuid, + order_number=entitlement_data['order_number'] + ) + assert course_entitlement.count() == 2 + def test_default_no_policy_entry(self): """ Verify that, when there are no entries in the course entitlement policy table, diff --git a/common/djangoapps/entitlements/migrations/0015_add_unique_together_constraint.py b/common/djangoapps/entitlements/migrations/0015_add_unique_together_constraint.py new file mode 100644 index 00000000000..cb6b1e54ea8 --- /dev/null +++ b/common/djangoapps/entitlements/migrations/0015_add_unique_together_constraint.py @@ -0,0 +1,29 @@ +# -*- coding: utf-8 -*- +# Generated by Django 1.11.27 on 2020-01-29 10:33 +from __future__ import unicode_literals + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('entitlements', '0014_auto_20200115_2022'), + ] + + operations = [ + migrations.AlterField( + model_name='courseentitlement', + name='order_number', + field=models.CharField(default=None, max_length=128, null=True), + ), + migrations.AlterField( + model_name='historicalcourseentitlement', + name='order_number', + field=models.CharField(default=None, max_length=128, null=True), + ), + migrations.AlterUniqueTogether( + name='courseentitlement', + unique_together=set([('course_uuid', 'order_number')]), + ), + ] diff --git a/common/djangoapps/entitlements/models.py b/common/djangoapps/entitlements/models.py index f018d3e0ba9..08e93690382 100644 --- a/common/djangoapps/entitlements/models.py +++ b/common/djangoapps/entitlements/models.py @@ -171,12 +171,15 @@ class CourseEntitlement(TimeStampedModel): blank=True, on_delete=models.CASCADE, ) - order_number = models.CharField(max_length=128, null=True, blank=True) + order_number = models.CharField(max_length=128, default=None, null=True) refund_locked = models.BooleanField(default=False) _policy = models.ForeignKey(CourseEntitlementPolicy, null=True, blank=True, on_delete=models.CASCADE) history = HistoricalRecords() + class Meta: + unique_together = ('course_uuid', 'order_number') + @property def expired_at_datetime(self): """ -- GitLab