Repository: tough-dev-school/education-backend

Issue:
Не работают триггеры для бандлов
https://sentry.io/organizations/fedor-borshev/issues/1403243325/?project=1807512&query=is%3Aunresolved


Discussion:

Resolving patch:
diff --git a/src/courses/models.py b/src/courses/models.py
--- a/src/courses/models.py
+++ b/src/courses/models.py
@@ -80,6 +80,9 @@ class Meta:
         verbose_name = _('Bundle')
         verbose_name_plural = _('Bundles')
 
+    def get_absolute_url(self):
+        return urljoin(settings.FRONTEND_URL, '/'.join(['bundles', self.slug, '']))
+
     def ship(self, to):
         for record in self.records.iterator():
             record.ship(to=to)
diff --git a/src/orders/models.py b/src/orders/models.py
--- a/src/orders/models.py
+++ b/src/orders/models.py
@@ -1,4 +1,4 @@
-from typing import Optional
+from typing import Iterable, Optional
 
 from django.utils import timezone
 from django.utils.translation import ugettext_lazy as _
@@ -59,18 +59,28 @@ def item(self):
                 if getattr(self, f'{field.name}_id', None) is not None:
                     return getattr(self, field.name)
 
+    @classmethod
+    def _iterate_items(cls) -> Iterable[models.fields.Field]:
+        for field in cls._meta.get_fields():
+            if getattr(field, '_is_item', False):
+                yield field
+
     @classmethod
     def get_item_foreignkey(cls, item) -> Optional[models.fields.Field]:
         """
         Given an item model, returns the ForeignKey to it"""
-        for field in cls._meta.get_fields():
-            if getattr(field, '_is_item', False):
-                if field.related_model == item.__class__:
-                    return field.name
+        for field in cls._iterate_items():
+            if field.related_model == item.__class__:
+                return field.name
+
+    def reset_items(self):
+        for field in self._iterate_items():
+            setattr(self, field.name, None)
 
     def set_item(self, item):
         foreign_key = self.__class__.get_item_foreignkey(item)
         if foreign_key is not None:
+            self.reset_items()
             setattr(self, foreign_key, item)
             return
 


Test patch:
diff --git a/src/orders/tests/order_content_type_replacement/tests_order_set_item.py b/src/orders/tests/order_content_type_replacement/tests_order_set_item.py
--- a/src/orders/tests/order_content_type_replacement/tests_order_set_item.py
+++ b/src/orders/tests/order_content_type_replacement/tests_order_set_item.py
@@ -41,3 +41,16 @@ def test_bundle(order, bundle):
 def test_exception_when_there_is_not_foreignkey(order):
     with pytest.raises(UnknownItemException):
         order.set_item(order)
+
+
+def test_setting_new_item_removes_the_old_one(order, course, bundle):
+    order.set_item(course)
+    order.save()
+
+    order.set_item(bundle)
+    order.save()
+
+    order.refresh_from_db()
+
+    assert order.bundle == bundle
+    assert order.course is None
diff --git a/src/triggers/tests/started_purchase_trigger/tests_started_purchase_trigger_template_context.py b/src/triggers/tests/started_purchase_trigger/tests_started_purchase_trigger_template_context.py
--- a/src/triggers/tests/started_purchase_trigger/tests_started_purchase_trigger_template_context.py
+++ b/src/triggers/tests/started_purchase_trigger/tests_started_purchase_trigger_template_context.py
@@ -8,6 +8,19 @@ def fix_frontend_url(settings):
     settings.FRONTEND_URL = 'https://frontend'
 
 
+@pytest.fixture
+def record(mixer, course):
+    return mixer.blend('courses.Record', course=course)
+
+
+@pytest.fixture
+def bundle(mixer, course):
+    bundle = mixer.blend('courses.Bundle')
+    bundle.courses.add(course)
+
+    return bundle
+
+
 def test(trigger):
     ctx = trigger.get_template_context()
 
@@ -15,3 +28,21 @@ def test(trigger):
     assert ctx['item_lower'] == 'билет на курс кройки и шитья'
     assert ctx['firstname'] == 'Камаз'
     assert 'https://frontend' in ctx['item_url']
+
+
+def test_with_record(trigger, record):
+    trigger.order.set_item(record)
+    trigger.order.save()
+
+    ctx = trigger.get_template_context()
+
+    assert 'https://frontend' in ctx['item_url']
+
+
+def test_with_bundle(trigger, bundle):
+    trigger.order.set_item(bundle)
+    trigger.order.save()
+
+    ctx = trigger.get_template_context()
+
+    assert 'https://frontend' in ctx['item_url']