We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Не работают триггеры для бандлов
https://sentry.io/organizations/fedor-borshev/issues/1403243325/?project=1807512&query=is%3Aunresolved

--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `src/orders/models.py`
Content:
```
1 from typing import Optional
2 
3 from django.utils import timezone
4 from django.utils.translation import ugettext_lazy as _
5 
6 from app.models import DefaultQuerySet, TimestampedModel, models
7 from orders.signals import order_got_shipped
8 
9 
10 class ItemField(models.ForeignKey):
11     """This is a simple replacement for the ContentType framework -- fields of this type
12     are fields linked to items
13     """
14     def __init__(self, *args, **kwargs):
15         self._is_item = True
16         super().__init__(*args, **kwargs)
17 
18 
19 class UnknownItemException(Exception):
20     pass
21 
22 
23 class OrderQuerySet(DefaultQuerySet):
24     def paid(self, invert=False):
25         return self.filter(paid__isnull=invert)
26 
27 
28 class Order(TimestampedModel):
29     objects = OrderQuerySet.as_manager()  # type: OrderQuerySet
30 
31     user = models.ForeignKey('users.User', on_delete=models.PROTECT)
32     price = models.DecimalField(max_digits=9, decimal_places=2)
33 
34     paid = models.DateTimeField(
35         _('Date when order got paid'),
36         null=True, blank=True,
37         help_text=_('If set during creation, order automaticaly gets shipped'),
38     )
39     shipped = models.DateTimeField(_('Date when order was shipped'), null=True, blank=True)
40 
41     course = ItemField('courses.Course', null=True, blank=True, on_delete=models.PROTECT)
42     record = ItemField('courses.Record', null=True, blank=True, on_delete=models.PROTECT)
43     bundle = ItemField('courses.Bundle', null=True, blank=True, on_delete=models.PROTECT)
44 
45     class Meta:
46         ordering = ['-id']
47         verbose_name = _('Order')
48         verbose_name_plural = _('Orders')
49 
50     def __str__(self):
51         return f'Order #{self.pk}'
52 
53     @property
54     def item(self):
55         """Find the attached item. Simple replacement for ContentType framework
56         """
57         for field in self.__class__._meta.get_fields():
58             if getattr(field, '_is_item', False):
59                 if getattr(self, f'{field.name}_id', None) is not None:
60                     return getattr(self, field.name)
61 
62     @classmethod
63     def get_item_foreignkey(cls, item) -> Optional[models.fields.Field]:
64         """
65         Given an item model, returns the ForeignKey to it"""
66         for field in cls._meta.get_fields():
67             if getattr(field, '_is_item', False):
68                 if field.related_model == item.__class__:
69                     return field.name
70 
71     def set_item(self, item):
72         foreign_key = self.__class__.get_item_foreignkey(item)
73         if foreign_key is not None:
74             setattr(self, foreign_key, item)
75             return
76 
77         raise UnknownItemException('There is not foreignKey for {}'.format(item.__class__))
78 
79     def set_paid(self):
80         is_already_paid = self.paid is not None
81 
82         self.paid = timezone.now()
83 
84         self.save()
85 
86         if not is_already_paid and self.item is not None:
87             self.ship()
88 
89     def ship(self):
90         """Ship the order. Better call it asynchronously"""
91         self.item.ship(to=self.user)
92 
93         self.shipped = timezone.now()
94 
95         self.save()
96 
97         order_got_shipped.send(
98             sender=self.__class__,
99             order=self,
100         )
101
```

Path: `src/courses/models.py`
Content:
```
1 from urllib.parse import urljoin
2 
3 from django.conf import settings
4 from django.utils.translation import ugettext_lazy as _
5 
6 from app.models import TimestampedModel, models
7 from app.s3 import AppS3
8 from shipping.mixins import Shippable
9 
10 
11 class Course(Shippable, TimestampedModel):
12     name = models.CharField(max_length=255)
13     name_genitive = models.CharField(_('Genitive name'), max_length=255, help_text='«мастер-класса о TDD». К примеру для записей.')
14     name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='«посещение мастер-класса по TDD» или «Доступ к записи курсов кройки и шитья»')
15     full_name = models.CharField(
16         _('Full name for letters'), max_length=255,
17         help_text='Билет на мастер-класс о TDD или «запись курсов кройки и шитья»',
18     )
19     slug = models.SlugField()
20     clickmeeting_room_url = models.URLField(_('Clickmeeting room URL'), null=True, blank=True, help_text=_('If set, every user who purcashes this course gets invited'))
21     template_id = models.CharField(_('Mailjet template_id'), max_length=256, blank=True, null=True, help_text=_('Leave it blank for the default template'))
22 
23     class Meta:
24         ordering = ['-id']
25         verbose_name = _('Course')
26         verbose_name_plural = _('Courses')
27 
28     def get_absolute_url(self):
29         return urljoin(settings.FRONTEND_URL, '/'.join(['courses', self.slug, '']))
30 
31 
32 class Record(Shippable, TimestampedModel):
33     course = models.ForeignKey(Course, on_delete=models.CASCADE)
34     name = models.CharField(max_length=255)
35     name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='«Доступ к записи курсов кройки и шитья»')
36     full_name = models.CharField(_('Full name for letters'), max_length=255, help_text='«Запись мастер-класса о TDD»')
37     slug = models.SlugField()
38     full_name = models.CharField(
39         _('Full name for letters'), max_length=255,
40         help_text='«Запись мастер-класса о TDD»',
41     )
42 
43     s3_object_id = models.CharField(max_length=512)
44     template_id = models.CharField(_('Mailjet template_id'), max_length=256, blank=True, null=True, help_text=_('Leave it blank for the default template'))
45 
46     class Meta:
47         ordering = ['-id']
48         verbose_name = _('Record')
49         verbose_name_plural = _('Records')
50 
51     @property
52     def name_genitive(self):
53         return self.course.name_genitive
54 
55     def get_url(self, expires: int = 3 * 24 * 60 * 60):
56         return AppS3().get_presigned_url(self.s3_object_id, expires=expires)
57 
58     def __str__(self):
59         return f'Запись {self.name_genitive}'
60 
61     def get_absolute_url(self):
62         return self.course.get_absolute_url()
63 
64 
65 class Bundle(Shippable, TimestampedModel):
66     records = models.ManyToManyField('courses.Record')
67     courses = models.ManyToManyField('courses.Course')
68 
69     name = models.CharField(max_length=255)
70     name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='«Доступ к записи курсов кройки и шитья»')
71     full_name = models.CharField(_('Full name for letters'), max_length=255, help_text='«Запись мастер-класса о TDD»')
72     slug = models.SlugField()
73     full_name = models.CharField(
74         _('Full name for letters'), max_length=255,
75         help_text='«Запись мастер-класса о TDD»',
76     )
77 
78     class Meta:
79         ordering = ['-id']
80         verbose_name = _('Bundle')
81         verbose_name_plural = _('Bundles')
82 
83     def ship(self, to):
84         for record in self.records.iterator():
85             record.ship(to=to)
86 
87         for course in self.courses.iterator():
88             course.ship(to=to)
89
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

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 @@
         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 @@
                 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

{"golden_diff": "diff --git a/src/courses/models.py b/src/courses/models.py\n--- a/src/courses/models.py\n+++ b/src/courses/models.py\n@@ -80,6 +80,9 @@\n         verbose_name = _('Bundle')\n         verbose_name_plural = _('Bundles')\n \n+    def get_absolute_url(self):\n+        return urljoin(settings.FRONTEND_URL, '/'.join(['bundles', self.slug, '']))\n+\n     def ship(self, to):\n         for record in self.records.iterator():\n             record.ship(to=to)\ndiff --git a/src/orders/models.py b/src/orders/models.py\n--- a/src/orders/models.py\n+++ b/src/orders/models.py\n@@ -1,4 +1,4 @@\n-from typing import Optional\n+from typing import Iterable, Optional\n \n from django.utils import timezone\n from django.utils.translation import ugettext_lazy as _\n@@ -59,18 +59,28 @@\n                 if getattr(self, f'{field.name}_id', None) is not None:\n                     return getattr(self, field.name)\n \n+    @classmethod\n+    def _iterate_items(cls) -> Iterable[models.fields.Field]:\n+        for field in cls._meta.get_fields():\n+            if getattr(field, '_is_item', False):\n+                yield field\n+\n     @classmethod\n     def get_item_foreignkey(cls, item) -> Optional[models.fields.Field]:\n         \"\"\"\n         Given an item model, returns the ForeignKey to it\"\"\"\n-        for field in cls._meta.get_fields():\n-            if getattr(field, '_is_item', False):\n-                if field.related_model == item.__class__:\n-                    return field.name\n+        for field in cls._iterate_items():\n+            if field.related_model == item.__class__:\n+                return field.name\n+\n+    def reset_items(self):\n+        for field in self._iterate_items():\n+            setattr(self, field.name, None)\n \n     def set_item(self, item):\n         foreign_key = self.__class__.get_item_foreignkey(item)\n         if foreign_key is not None:\n+            self.reset_items()\n             setattr(self, foreign_key, item)\n             return\n", "issue": "\u041d\u0435 \u0440\u0430\u0431\u043e\u0442\u0430\u044e\u0442 \u0442\u0440\u0438\u0433\u0433\u0435\u0440\u044b \u0434\u043b\u044f \u0431\u0430\u043d\u0434\u043b\u043e\u0432\nhttps://sentry.io/organizations/fedor-borshev/issues/1403243325/?project=1807512&query=is%3Aunresolved\n", "before_files": [{"content": "from typing import Optional\n\nfrom django.utils import timezone\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom app.models import DefaultQuerySet, TimestampedModel, models\nfrom orders.signals import order_got_shipped\n\n\nclass ItemField(models.ForeignKey):\n    \"\"\"This is a simple replacement for the ContentType framework -- fields of this type\n    are fields linked to items\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self._is_item = True\n        super().__init__(*args, **kwargs)\n\n\nclass UnknownItemException(Exception):\n    pass\n\n\nclass OrderQuerySet(DefaultQuerySet):\n    def paid(self, invert=False):\n        return self.filter(paid__isnull=invert)\n\n\nclass Order(TimestampedModel):\n    objects = OrderQuerySet.as_manager()  # type: OrderQuerySet\n\n    user = models.ForeignKey('users.User', on_delete=models.PROTECT)\n    price = models.DecimalField(max_digits=9, decimal_places=2)\n\n    paid = models.DateTimeField(\n        _('Date when order got paid'),\n        null=True, blank=True,\n        help_text=_('If set during creation, order automaticaly gets shipped'),\n    )\n    shipped = models.DateTimeField(_('Date when order was shipped'), null=True, blank=True)\n\n    course = ItemField('courses.Course', null=True, blank=True, on_delete=models.PROTECT)\n    record = ItemField('courses.Record', null=True, blank=True, on_delete=models.PROTECT)\n    bundle = ItemField('courses.Bundle', null=True, blank=True, on_delete=models.PROTECT)\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Order')\n        verbose_name_plural = _('Orders')\n\n    def __str__(self):\n        return f'Order #{self.pk}'\n\n    @property\n    def item(self):\n        \"\"\"Find the attached item. Simple replacement for ContentType framework\n        \"\"\"\n        for field in self.__class__._meta.get_fields():\n            if getattr(field, '_is_item', False):\n                if getattr(self, f'{field.name}_id', None) is not None:\n                    return getattr(self, field.name)\n\n    @classmethod\n    def get_item_foreignkey(cls, item) -> Optional[models.fields.Field]:\n        \"\"\"\n        Given an item model, returns the ForeignKey to it\"\"\"\n        for field in cls._meta.get_fields():\n            if getattr(field, '_is_item', False):\n                if field.related_model == item.__class__:\n                    return field.name\n\n    def set_item(self, item):\n        foreign_key = self.__class__.get_item_foreignkey(item)\n        if foreign_key is not None:\n            setattr(self, foreign_key, item)\n            return\n\n        raise UnknownItemException('There is not foreignKey for {}'.format(item.__class__))\n\n    def set_paid(self):\n        is_already_paid = self.paid is not None\n\n        self.paid = timezone.now()\n\n        self.save()\n\n        if not is_already_paid and self.item is not None:\n            self.ship()\n\n    def ship(self):\n        \"\"\"Ship the order. Better call it asynchronously\"\"\"\n        self.item.ship(to=self.user)\n\n        self.shipped = timezone.now()\n\n        self.save()\n\n        order_got_shipped.send(\n            sender=self.__class__,\n            order=self,\n        )\n", "path": "src/orders/models.py"}, {"content": "from urllib.parse import urljoin\n\nfrom django.conf import settings\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom app.models import TimestampedModel, models\nfrom app.s3 import AppS3\nfrom shipping.mixins import Shippable\n\n\nclass Course(Shippable, TimestampedModel):\n    name = models.CharField(max_length=255)\n    name_genitive = models.CharField(_('Genitive name'), max_length=255, help_text='\u00ab\u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb. \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439.')\n    name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='\u00ab\u043f\u043e\u0441\u0435\u0449\u0435\u043d\u0438\u0435 \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u043e TDD\u00bb \u0438\u043b\u0438 \u00ab\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb')\n    full_name = models.CharField(\n        _('Full name for letters'), max_length=255,\n        help_text='\u0411\u0438\u043b\u0435\u0442 \u043d\u0430 \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441 \u043e TDD \u0438\u043b\u0438 \u00ab\u0437\u0430\u043f\u0438\u0441\u044c \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb',\n    )\n    slug = models.SlugField()\n    clickmeeting_room_url = models.URLField(_('Clickmeeting room URL'), null=True, blank=True, help_text=_('If set, every user who purcashes this course gets invited'))\n    template_id = models.CharField(_('Mailjet template_id'), max_length=256, blank=True, null=True, help_text=_('Leave it blank for the default template'))\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Course')\n        verbose_name_plural = _('Courses')\n\n    def get_absolute_url(self):\n        return urljoin(settings.FRONTEND_URL, '/'.join(['courses', self.slug, '']))\n\n\nclass Record(Shippable, TimestampedModel):\n    course = models.ForeignKey(Course, on_delete=models.CASCADE)\n    name = models.CharField(max_length=255)\n    name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='\u00ab\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb')\n    full_name = models.CharField(_('Full name for letters'), max_length=255, help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb')\n    slug = models.SlugField()\n    full_name = models.CharField(\n        _('Full name for letters'), max_length=255,\n        help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb',\n    )\n\n    s3_object_id = models.CharField(max_length=512)\n    template_id = models.CharField(_('Mailjet template_id'), max_length=256, blank=True, null=True, help_text=_('Leave it blank for the default template'))\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Record')\n        verbose_name_plural = _('Records')\n\n    @property\n    def name_genitive(self):\n        return self.course.name_genitive\n\n    def get_url(self, expires: int = 3 * 24 * 60 * 60):\n        return AppS3().get_presigned_url(self.s3_object_id, expires=expires)\n\n    def __str__(self):\n        return f'\u0417\u0430\u043f\u0438\u0441\u044c {self.name_genitive}'\n\n    def get_absolute_url(self):\n        return self.course.get_absolute_url()\n\n\nclass Bundle(Shippable, TimestampedModel):\n    records = models.ManyToManyField('courses.Record')\n    courses = models.ManyToManyField('courses.Course')\n\n    name = models.CharField(max_length=255)\n    name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='\u00ab\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb')\n    full_name = models.CharField(_('Full name for letters'), max_length=255, help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb')\n    slug = models.SlugField()\n    full_name = models.CharField(\n        _('Full name for letters'), max_length=255,\n        help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb',\n    )\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Bundle')\n        verbose_name_plural = _('Bundles')\n\n    def ship(self, to):\n        for record in self.records.iterator():\n            record.ship(to=to)\n\n        for course in self.courses.iterator():\n            course.ship(to=to)\n", "path": "src/courses/models.py"}], "after_files": [{"content": "from typing import Iterable, Optional\n\nfrom django.utils import timezone\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom app.models import DefaultQuerySet, TimestampedModel, models\nfrom orders.signals import order_got_shipped\n\n\nclass ItemField(models.ForeignKey):\n    \"\"\"This is a simple replacement for the ContentType framework -- fields of this type\n    are fields linked to items\n    \"\"\"\n    def __init__(self, *args, **kwargs):\n        self._is_item = True\n        super().__init__(*args, **kwargs)\n\n\nclass UnknownItemException(Exception):\n    pass\n\n\nclass OrderQuerySet(DefaultQuerySet):\n    def paid(self, invert=False):\n        return self.filter(paid__isnull=invert)\n\n\nclass Order(TimestampedModel):\n    objects = OrderQuerySet.as_manager()  # type: OrderQuerySet\n\n    user = models.ForeignKey('users.User', on_delete=models.PROTECT)\n    price = models.DecimalField(max_digits=9, decimal_places=2)\n\n    paid = models.DateTimeField(\n        _('Date when order got paid'),\n        null=True, blank=True,\n        help_text=_('If set during creation, order automaticaly gets shipped'),\n    )\n    shipped = models.DateTimeField(_('Date when order was shipped'), null=True, blank=True)\n\n    course = ItemField('courses.Course', null=True, blank=True, on_delete=models.PROTECT)\n    record = ItemField('courses.Record', null=True, blank=True, on_delete=models.PROTECT)\n    bundle = ItemField('courses.Bundle', null=True, blank=True, on_delete=models.PROTECT)\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Order')\n        verbose_name_plural = _('Orders')\n\n    def __str__(self):\n        return f'Order #{self.pk}'\n\n    @property\n    def item(self):\n        \"\"\"Find the attached item. Simple replacement for ContentType framework\n        \"\"\"\n        for field in self.__class__._meta.get_fields():\n            if getattr(field, '_is_item', False):\n                if getattr(self, f'{field.name}_id', None) is not None:\n                    return getattr(self, field.name)\n\n    @classmethod\n    def _iterate_items(cls) -> Iterable[models.fields.Field]:\n        for field in cls._meta.get_fields():\n            if getattr(field, '_is_item', False):\n                yield field\n\n    @classmethod\n    def get_item_foreignkey(cls, item) -> Optional[models.fields.Field]:\n        \"\"\"\n        Given an item model, returns the ForeignKey to it\"\"\"\n        for field in cls._iterate_items():\n            if field.related_model == item.__class__:\n                return field.name\n\n    def reset_items(self):\n        for field in self._iterate_items():\n            setattr(self, field.name, None)\n\n    def set_item(self, item):\n        foreign_key = self.__class__.get_item_foreignkey(item)\n        if foreign_key is not None:\n            self.reset_items()\n            setattr(self, foreign_key, item)\n            return\n\n        raise UnknownItemException('There is not foreignKey for {}'.format(item.__class__))\n\n    def set_paid(self):\n        is_already_paid = self.paid is not None\n\n        self.paid = timezone.now()\n\n        self.save()\n\n        if not is_already_paid and self.item is not None:\n            self.ship()\n\n    def ship(self):\n        \"\"\"Ship the order. Better call it asynchronously\"\"\"\n        self.item.ship(to=self.user)\n\n        self.shipped = timezone.now()\n\n        self.save()\n\n        order_got_shipped.send(\n            sender=self.__class__,\n            order=self,\n        )\n", "path": "src/orders/models.py"}, {"content": "from urllib.parse import urljoin\n\nfrom django.conf import settings\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom app.models import TimestampedModel, models\nfrom app.s3 import AppS3\nfrom shipping.mixins import Shippable\n\n\nclass Course(Shippable, TimestampedModel):\n    name = models.CharField(max_length=255)\n    name_genitive = models.CharField(_('Genitive name'), max_length=255, help_text='\u00ab\u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb. \u041a \u043f\u0440\u0438\u043c\u0435\u0440\u0443 \u0434\u043b\u044f \u0437\u0430\u043f\u0438\u0441\u0435\u0439.')\n    name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='\u00ab\u043f\u043e\u0441\u0435\u0449\u0435\u043d\u0438\u0435 \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043f\u043e TDD\u00bb \u0438\u043b\u0438 \u00ab\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb')\n    full_name = models.CharField(\n        _('Full name for letters'), max_length=255,\n        help_text='\u0411\u0438\u043b\u0435\u0442 \u043d\u0430 \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441 \u043e TDD \u0438\u043b\u0438 \u00ab\u0437\u0430\u043f\u0438\u0441\u044c \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb',\n    )\n    slug = models.SlugField()\n    clickmeeting_room_url = models.URLField(_('Clickmeeting room URL'), null=True, blank=True, help_text=_('If set, every user who purcashes this course gets invited'))\n    template_id = models.CharField(_('Mailjet template_id'), max_length=256, blank=True, null=True, help_text=_('Leave it blank for the default template'))\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Course')\n        verbose_name_plural = _('Courses')\n\n    def get_absolute_url(self):\n        return urljoin(settings.FRONTEND_URL, '/'.join(['courses', self.slug, '']))\n\n\nclass Record(Shippable, TimestampedModel):\n    course = models.ForeignKey(Course, on_delete=models.CASCADE)\n    name = models.CharField(max_length=255)\n    name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='\u00ab\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb')\n    full_name = models.CharField(_('Full name for letters'), max_length=255, help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb')\n    slug = models.SlugField()\n    full_name = models.CharField(\n        _('Full name for letters'), max_length=255,\n        help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb',\n    )\n\n    s3_object_id = models.CharField(max_length=512)\n    template_id = models.CharField(_('Mailjet template_id'), max_length=256, blank=True, null=True, help_text=_('Leave it blank for the default template'))\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Record')\n        verbose_name_plural = _('Records')\n\n    @property\n    def name_genitive(self):\n        return self.course.name_genitive\n\n    def get_url(self, expires: int = 3 * 24 * 60 * 60):\n        return AppS3().get_presigned_url(self.s3_object_id, expires=expires)\n\n    def __str__(self):\n        return f'\u0417\u0430\u043f\u0438\u0441\u044c {self.name_genitive}'\n\n    def get_absolute_url(self):\n        return self.course.get_absolute_url()\n\n\nclass Bundle(Shippable, TimestampedModel):\n    records = models.ManyToManyField('courses.Record')\n    courses = models.ManyToManyField('courses.Course')\n\n    name = models.CharField(max_length=255)\n    name_receipt = models.CharField(_('Name for receipts'), max_length=255, help_text='\u00ab\u0414\u043e\u0441\u0442\u0443\u043f \u043a \u0437\u0430\u043f\u0438\u0441\u0438 \u043a\u0443\u0440\u0441\u043e\u0432 \u043a\u0440\u043e\u0439\u043a\u0438 \u0438 \u0448\u0438\u0442\u044c\u044f\u00bb')\n    full_name = models.CharField(_('Full name for letters'), max_length=255, help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb')\n    slug = models.SlugField()\n    full_name = models.CharField(\n        _('Full name for letters'), max_length=255,\n        help_text='\u00ab\u0417\u0430\u043f\u0438\u0441\u044c \u043c\u0430\u0441\u0442\u0435\u0440-\u043a\u043b\u0430\u0441\u0441\u0430 \u043e TDD\u00bb',\n    )\n\n    class Meta:\n        ordering = ['-id']\n        verbose_name = _('Bundle')\n        verbose_name_plural = _('Bundles')\n\n    def get_absolute_url(self):\n        return urljoin(settings.FRONTEND_URL, '/'.join(['bundles', self.slug, '']))\n\n    def ship(self, to):\n        for record in self.records.iterator():\n            record.ship(to=to)\n\n        for course in self.courses.iterator():\n            course.ship(to=to)\n", "path": "src/courses/models.py"}]}