We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
Calculate updates from baseline, not from actual
## Test plan

There shouldn't be a difference from the original results framework. No specific testing needed.
## Issue description

Currently, the place of the updates on the slider is calculated by going back from the actual. However, this sometimes results in strange behaviour (e.g. the slider being before the baseline). We should calculate starting from the baseline and add up all the previous updates.


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `akvo/rsr/models/project_update.py`
Content:
```
1 # -*- coding: utf-8 -*-
2 
3 # Akvo RSR is covered by the GNU Affero General Public License.
4 # See more details in the license.txt file located at the root folder of the Akvo RSR module.
5 # For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
6 
7 
8 from datetime import datetime, timedelta
9 from decimal import Decimal, InvalidOperation
10 
11 from django.conf import settings
12 from django.core.exceptions import ValidationError
13 from django.db import models
14 from django.utils.translation import ugettext_lazy as _
15 
16 from django_counter.models import ViewCounter
17 
18 from sorl.thumbnail.fields import ImageField
19 from embed_video.fields import EmbedVideoField
20 
21 from akvo.utils import rsr_image_path, to_gmt
22 
23 from ..fields import ValidXMLCharField, ValidXMLTextField
24 from ..mixins import TimestampsMixin
25 
26 
27 def image_path(instance, file_name):
28     """Create a path like 'db/project/<update.project.id>/update/<update.id>/image_name.ext'"""
29     path = 'db/project/%d/update/%%(instance_pk)s/%%(file_name)s' % instance.project.pk
30     return rsr_image_path(instance, file_name, path)
31 
32 
33 class ProjectUpdate(TimestampsMixin, models.Model):
34     UPDATE_METHODS = (
35         ('W', _(u'web')),
36         ('E', _(u'e-mail')),
37         ('S', _(u'SMS')),
38         ('M', _(u'mobile')),
39     )
40 
41     project = models.ForeignKey('Project', related_name='project_updates',
42                                 verbose_name=_(u'project'))
43     user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_(u'user'))
44     title = ValidXMLCharField(_(u'title'), max_length=80, db_index=True,
45                               help_text=_(u'80 characters'))
46     text = ValidXMLTextField(_(u'text'), blank=True)
47     language = ValidXMLCharField(max_length=2, choices=settings.LANGUAGES, default='en',
48                                  help_text=_(u'The language of the update'))
49     primary_location = models.ForeignKey('ProjectUpdateLocation', null=True, blank=True,
50                                          on_delete=models.SET_NULL)
51     photo = ImageField(_(u'photo'), blank=True, upload_to=image_path,
52                        help_text=_(u'The image should have 4:3 height:width ratio for best '
53                                    u'displaying result'))
54     photo_caption = ValidXMLCharField(_(u'photo caption'), blank=True, max_length=75,
55                                       help_text=_(u'75 characters'))
56     photo_credit = ValidXMLCharField(_(u'photo credit'), blank=True, max_length=75,
57                                      help_text=_(u'75 characters'))
58     video = EmbedVideoField(_(u'video URL'), blank=True,
59                             help_text=_(u'Supported providers: YouTube and Vimeo'))
60     video_caption = ValidXMLCharField(_(u'video caption'), blank=True, max_length=75,
61                                       help_text=_(u'75 characters'))
62     video_credit = ValidXMLCharField(_(u'video credit'), blank=True, max_length=75,
63                                      help_text=_(u'75 characters'))
64     update_method = ValidXMLCharField(_(u'update method'), blank=True, max_length=1,
65                                       choices=UPDATE_METHODS, db_index=True, default='W')
66     user_agent = ValidXMLCharField(_(u'user agent'), blank=True, max_length=200, default='')
67     uuid = ValidXMLCharField(_(u'uuid'), blank=True, max_length=40, default='', db_index=True,
68                              help_text=_(u'Universally unique ID set by creating user agent'))
69     notes = ValidXMLTextField(verbose_name=_(u"Notes and comments"), blank=True, default='')
70 
71     # Indicator updates
72     indicator_period = models.ForeignKey('IndicatorPeriod', related_name='updates',
73                                          verbose_name=_(u'indicator period'), blank=True, null=True)
74     period_update = models.DecimalField(_(u'period update'), blank=True, null=True, max_digits=14,
75                                         decimal_places=2)
76 
77     class Meta:
78         app_label = 'rsr'
79         get_latest_by = "created_at"
80         verbose_name = _(u'project update')
81         verbose_name_plural = _(u'project updates')
82         ordering = ['-id', ]
83 
84     def save(self, *args, **kwargs):
85         if self.indicator_period and self.period_update:
86             if not self.pk:
87                 # Newly created update to indicator period, update the actual value.
88                 self.indicator_period.update_actual_value(self.period_update)
89 
90             else:
91                 # Update to already existing indicator period, check if values have been changed.
92                 orig_update = ProjectUpdate.objects.get(pk=self.pk)
93                 if orig_update.indicator_period != self.indicator_period:
94                     # Indicator period has changed. Substract value from old period, and add new
95                     # value to new period.
96                     try:
97                         orig_update.update_actual_value(Decimal(orig_update.period_update) * -1)
98                     except (InvalidOperation, TypeError):
99                         pass
100                     self.indicator_period.update_actual_value(self.period_update)
101 
102                 elif orig_update.period_update != self.period_update:
103                     # Indicator value has changed. Add the difference to it.
104                     try:
105                         self.indicator_period.update_actual_value(
106                             Decimal(self.period_update) - Decimal(orig_update.period_update)
107                         )
108                     except (InvalidOperation, TypeError):
109                         self.indicator_period.update_actual_value(self.period_update)
110 
111         super(ProjectUpdate, self).save(*args, **kwargs)
112 
113     def delete(self, *args, **kwargs):
114         if self.indicator_period and self.period_update:
115             try:
116                 self.indicator_period.update_actual_value(
117                     Decimal(self.period_update) * -1
118                 )
119             except (InvalidOperation, TypeError):
120                 pass
121         super(ProjectUpdate, self).delete(*args, **kwargs)
122 
123     def clean(self):
124         if hasattr(self, 'project') and hasattr(self, 'indicator_period') and \
125                 hasattr(self, 'period_update'):
126             validation_errors = {}
127 
128             # Don't allow an indicator period that belongs to a different project
129             if self.project and self.indicator_period:
130                 if not self.indicator_period.indicator.result.project == self.project:
131                     validation_errors['indicator_period'] = u'%s' % _(
132                         u'Indicator period must be part of the same project'
133                     )
134 
135             # Don't allow an indicator update to a non-Impact project
136             if self.indicator_period and self.period_update and not self.project.is_impact_project:
137                 validation_errors['project'] = u'%s' % _(
138                     u'Project must be an Impact project to place indicator updates to it'
139                 )
140 
141             if validation_errors:
142                 raise ValidationError(validation_errors)
143 
144     def img(self, value=''):
145         try:
146             return self.photo.thumbnail_tag
147         except:
148             return value
149     img.allow_tags = True
150 
151     def edit_window_has_expired(self):
152         """Determine whether or not update timeout window has expired.
153         The timeout is controlled by settings.PROJECT_UPDATE_TIMEOUT and
154         defaults to 30 minutes.
155         """
156         return (datetime.now() - self.created_at) > self.edit_timeout
157 
158     @property
159     def expires_at(self):
160         return to_gmt(self.created_at + self.edit_timeout)
161 
162     @property
163     def edit_timeout(self):
164         timeout_minutes = getattr(settings, 'PROJECT_UPDATE_TIMEOUT', 30)
165         return timedelta(minutes=timeout_minutes)
166 
167     @property
168     def edit_time_remaining(self):
169         return self.edit_timeout - self.created_at
170 
171     @property
172     def time_gmt(self):
173         return to_gmt(self.created_at)
174 
175     @property
176     def time_last_updated_gmt(self):
177         return to_gmt(self.last_modified_at)
178 
179     @property
180     def view_count(self):
181         counter = ViewCounter.objects.get_for_object(self)
182         return counter.count or 0
183 
184     @models.permalink
185     def get_absolute_url(self):
186         return 'update-main', (), {'project_id': self.project.pk, 'update_id': self.pk}
187 
188     def __unicode__(self):
189         return _(u'Project update for %(project_name)s') % {'project_name': self.project.title}
190
```
--- 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/akvo/rsr/models/project_update.py b/akvo/rsr/models/project_update.py
--- a/akvo/rsr/models/project_update.py
+++ b/akvo/rsr/models/project_update.py
@@ -112,12 +112,19 @@
 
     def delete(self, *args, **kwargs):
         if self.indicator_period and self.period_update:
-            try:
-                self.indicator_period.update_actual_value(
-                    Decimal(self.period_update) * -1
-                )
-            except (InvalidOperation, TypeError):
-                pass
+            # Subsctract the value of the update from the actual value of the indicator period
+            if ProjectUpdate.objects.filter(indicator_period=self.indicator_period).\
+                    exclude(pk=self.pk).exists():
+                try:
+                    self.indicator_period.update_actual_value(
+                        Decimal(self.period_update) * -1
+                    )
+                except (InvalidOperation, TypeError):
+                    pass
+            else:
+                # There's no other updates for this indicator period, remove actual value
+                self.indicator_period.actual_value = ''
+                self.indicator_period.save()
         super(ProjectUpdate, self).delete(*args, **kwargs)
 
     def clean(self):

{"golden_diff": "diff --git a/akvo/rsr/models/project_update.py b/akvo/rsr/models/project_update.py\n--- a/akvo/rsr/models/project_update.py\n+++ b/akvo/rsr/models/project_update.py\n@@ -112,12 +112,19 @@\n \n     def delete(self, *args, **kwargs):\n         if self.indicator_period and self.period_update:\n-            try:\n-                self.indicator_period.update_actual_value(\n-                    Decimal(self.period_update) * -1\n-                )\n-            except (InvalidOperation, TypeError):\n-                pass\n+            # Subsctract the value of the update from the actual value of the indicator period\n+            if ProjectUpdate.objects.filter(indicator_period=self.indicator_period).\\\n+                    exclude(pk=self.pk).exists():\n+                try:\n+                    self.indicator_period.update_actual_value(\n+                        Decimal(self.period_update) * -1\n+                    )\n+                except (InvalidOperation, TypeError):\n+                    pass\n+            else:\n+                # There's no other updates for this indicator period, remove actual value\n+                self.indicator_period.actual_value = ''\n+                self.indicator_period.save()\n         super(ProjectUpdate, self).delete(*args, **kwargs)\n \n     def clean(self):\n", "issue": "Calculate updates from baseline, not from actual\n## Test plan\n\nThere shouldn't be a difference from the original results framework. No specific testing needed.\n## Issue description\n\nCurrently, the place of the updates on the slider is calculated by going back from the actual. However, this sometimes results in strange behaviour (e.g. the slider being before the baseline). We should calculate starting from the baseline and add up all the previous updates.\n\n", "before_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Akvo RSR is covered by the GNU Affero General Public License.\n# See more details in the license.txt file located at the root folder of the Akvo RSR module.\n# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\n\nfrom datetime import datetime, timedelta\nfrom decimal import Decimal, InvalidOperation\n\nfrom django.conf import settings\nfrom django.core.exceptions import ValidationError\nfrom django.db import models\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom django_counter.models import ViewCounter\n\nfrom sorl.thumbnail.fields import ImageField\nfrom embed_video.fields import EmbedVideoField\n\nfrom akvo.utils import rsr_image_path, to_gmt\n\nfrom ..fields import ValidXMLCharField, ValidXMLTextField\nfrom ..mixins import TimestampsMixin\n\n\ndef image_path(instance, file_name):\n    \"\"\"Create a path like 'db/project/<update.project.id>/update/<update.id>/image_name.ext'\"\"\"\n    path = 'db/project/%d/update/%%(instance_pk)s/%%(file_name)s' % instance.project.pk\n    return rsr_image_path(instance, file_name, path)\n\n\nclass ProjectUpdate(TimestampsMixin, models.Model):\n    UPDATE_METHODS = (\n        ('W', _(u'web')),\n        ('E', _(u'e-mail')),\n        ('S', _(u'SMS')),\n        ('M', _(u'mobile')),\n    )\n\n    project = models.ForeignKey('Project', related_name='project_updates',\n                                verbose_name=_(u'project'))\n    user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_(u'user'))\n    title = ValidXMLCharField(_(u'title'), max_length=80, db_index=True,\n                              help_text=_(u'80 characters'))\n    text = ValidXMLTextField(_(u'text'), blank=True)\n    language = ValidXMLCharField(max_length=2, choices=settings.LANGUAGES, default='en',\n                                 help_text=_(u'The language of the update'))\n    primary_location = models.ForeignKey('ProjectUpdateLocation', null=True, blank=True,\n                                         on_delete=models.SET_NULL)\n    photo = ImageField(_(u'photo'), blank=True, upload_to=image_path,\n                       help_text=_(u'The image should have 4:3 height:width ratio for best '\n                                   u'displaying result'))\n    photo_caption = ValidXMLCharField(_(u'photo caption'), blank=True, max_length=75,\n                                      help_text=_(u'75 characters'))\n    photo_credit = ValidXMLCharField(_(u'photo credit'), blank=True, max_length=75,\n                                     help_text=_(u'75 characters'))\n    video = EmbedVideoField(_(u'video URL'), blank=True,\n                            help_text=_(u'Supported providers: YouTube and Vimeo'))\n    video_caption = ValidXMLCharField(_(u'video caption'), blank=True, max_length=75,\n                                      help_text=_(u'75 characters'))\n    video_credit = ValidXMLCharField(_(u'video credit'), blank=True, max_length=75,\n                                     help_text=_(u'75 characters'))\n    update_method = ValidXMLCharField(_(u'update method'), blank=True, max_length=1,\n                                      choices=UPDATE_METHODS, db_index=True, default='W')\n    user_agent = ValidXMLCharField(_(u'user agent'), blank=True, max_length=200, default='')\n    uuid = ValidXMLCharField(_(u'uuid'), blank=True, max_length=40, default='', db_index=True,\n                             help_text=_(u'Universally unique ID set by creating user agent'))\n    notes = ValidXMLTextField(verbose_name=_(u\"Notes and comments\"), blank=True, default='')\n\n    # Indicator updates\n    indicator_period = models.ForeignKey('IndicatorPeriod', related_name='updates',\n                                         verbose_name=_(u'indicator period'), blank=True, null=True)\n    period_update = models.DecimalField(_(u'period update'), blank=True, null=True, max_digits=14,\n                                        decimal_places=2)\n\n    class Meta:\n        app_label = 'rsr'\n        get_latest_by = \"created_at\"\n        verbose_name = _(u'project update')\n        verbose_name_plural = _(u'project updates')\n        ordering = ['-id', ]\n\n    def save(self, *args, **kwargs):\n        if self.indicator_period and self.period_update:\n            if not self.pk:\n                # Newly created update to indicator period, update the actual value.\n                self.indicator_period.update_actual_value(self.period_update)\n\n            else:\n                # Update to already existing indicator period, check if values have been changed.\n                orig_update = ProjectUpdate.objects.get(pk=self.pk)\n                if orig_update.indicator_period != self.indicator_period:\n                    # Indicator period has changed. Substract value from old period, and add new\n                    # value to new period.\n                    try:\n                        orig_update.update_actual_value(Decimal(orig_update.period_update) * -1)\n                    except (InvalidOperation, TypeError):\n                        pass\n                    self.indicator_period.update_actual_value(self.period_update)\n\n                elif orig_update.period_update != self.period_update:\n                    # Indicator value has changed. Add the difference to it.\n                    try:\n                        self.indicator_period.update_actual_value(\n                            Decimal(self.period_update) - Decimal(orig_update.period_update)\n                        )\n                    except (InvalidOperation, TypeError):\n                        self.indicator_period.update_actual_value(self.period_update)\n\n        super(ProjectUpdate, self).save(*args, **kwargs)\n\n    def delete(self, *args, **kwargs):\n        if self.indicator_period and self.period_update:\n            try:\n                self.indicator_period.update_actual_value(\n                    Decimal(self.period_update) * -1\n                )\n            except (InvalidOperation, TypeError):\n                pass\n        super(ProjectUpdate, self).delete(*args, **kwargs)\n\n    def clean(self):\n        if hasattr(self, 'project') and hasattr(self, 'indicator_period') and \\\n                hasattr(self, 'period_update'):\n            validation_errors = {}\n\n            # Don't allow an indicator period that belongs to a different project\n            if self.project and self.indicator_period:\n                if not self.indicator_period.indicator.result.project == self.project:\n                    validation_errors['indicator_period'] = u'%s' % _(\n                        u'Indicator period must be part of the same project'\n                    )\n\n            # Don't allow an indicator update to a non-Impact project\n            if self.indicator_period and self.period_update and not self.project.is_impact_project:\n                validation_errors['project'] = u'%s' % _(\n                    u'Project must be an Impact project to place indicator updates to it'\n                )\n\n            if validation_errors:\n                raise ValidationError(validation_errors)\n\n    def img(self, value=''):\n        try:\n            return self.photo.thumbnail_tag\n        except:\n            return value\n    img.allow_tags = True\n\n    def edit_window_has_expired(self):\n        \"\"\"Determine whether or not update timeout window has expired.\n        The timeout is controlled by settings.PROJECT_UPDATE_TIMEOUT and\n        defaults to 30 minutes.\n        \"\"\"\n        return (datetime.now() - self.created_at) > self.edit_timeout\n\n    @property\n    def expires_at(self):\n        return to_gmt(self.created_at + self.edit_timeout)\n\n    @property\n    def edit_timeout(self):\n        timeout_minutes = getattr(settings, 'PROJECT_UPDATE_TIMEOUT', 30)\n        return timedelta(minutes=timeout_minutes)\n\n    @property\n    def edit_time_remaining(self):\n        return self.edit_timeout - self.created_at\n\n    @property\n    def time_gmt(self):\n        return to_gmt(self.created_at)\n\n    @property\n    def time_last_updated_gmt(self):\n        return to_gmt(self.last_modified_at)\n\n    @property\n    def view_count(self):\n        counter = ViewCounter.objects.get_for_object(self)\n        return counter.count or 0\n\n    @models.permalink\n    def get_absolute_url(self):\n        return 'update-main', (), {'project_id': self.project.pk, 'update_id': self.pk}\n\n    def __unicode__(self):\n        return _(u'Project update for %(project_name)s') % {'project_name': self.project.title}\n", "path": "akvo/rsr/models/project_update.py"}], "after_files": [{"content": "# -*- coding: utf-8 -*-\n\n# Akvo RSR is covered by the GNU Affero General Public License.\n# See more details in the license.txt file located at the root folder of the Akvo RSR module.\n# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.\n\n\nfrom datetime import datetime, timedelta\nfrom decimal import Decimal, InvalidOperation\n\nfrom django.conf import settings\nfrom django.core.exceptions import ValidationError\nfrom django.db import models\nfrom django.utils.translation import ugettext_lazy as _\n\nfrom django_counter.models import ViewCounter\n\nfrom sorl.thumbnail.fields import ImageField\nfrom embed_video.fields import EmbedVideoField\n\nfrom akvo.utils import rsr_image_path, to_gmt\n\nfrom ..fields import ValidXMLCharField, ValidXMLTextField\nfrom ..mixins import TimestampsMixin\n\n\ndef image_path(instance, file_name):\n    \"\"\"Create a path like 'db/project/<update.project.id>/update/<update.id>/image_name.ext'\"\"\"\n    path = 'db/project/%d/update/%%(instance_pk)s/%%(file_name)s' % instance.project.pk\n    return rsr_image_path(instance, file_name, path)\n\n\nclass ProjectUpdate(TimestampsMixin, models.Model):\n    UPDATE_METHODS = (\n        ('W', _(u'web')),\n        ('E', _(u'e-mail')),\n        ('S', _(u'SMS')),\n        ('M', _(u'mobile')),\n    )\n\n    project = models.ForeignKey('Project', related_name='project_updates',\n                                verbose_name=_(u'project'))\n    user = models.ForeignKey(settings.AUTH_USER_MODEL, verbose_name=_(u'user'))\n    title = ValidXMLCharField(_(u'title'), max_length=80, db_index=True,\n                              help_text=_(u'80 characters'))\n    text = ValidXMLTextField(_(u'text'), blank=True)\n    language = ValidXMLCharField(max_length=2, choices=settings.LANGUAGES, default='en',\n                                 help_text=_(u'The language of the update'))\n    primary_location = models.ForeignKey('ProjectUpdateLocation', null=True, blank=True,\n                                         on_delete=models.SET_NULL)\n    photo = ImageField(_(u'photo'), blank=True, upload_to=image_path,\n                       help_text=_(u'The image should have 4:3 height:width ratio for best '\n                                   u'displaying result'))\n    photo_caption = ValidXMLCharField(_(u'photo caption'), blank=True, max_length=75,\n                                      help_text=_(u'75 characters'))\n    photo_credit = ValidXMLCharField(_(u'photo credit'), blank=True, max_length=75,\n                                     help_text=_(u'75 characters'))\n    video = EmbedVideoField(_(u'video URL'), blank=True,\n                            help_text=_(u'Supported providers: YouTube and Vimeo'))\n    video_caption = ValidXMLCharField(_(u'video caption'), blank=True, max_length=75,\n                                      help_text=_(u'75 characters'))\n    video_credit = ValidXMLCharField(_(u'video credit'), blank=True, max_length=75,\n                                     help_text=_(u'75 characters'))\n    update_method = ValidXMLCharField(_(u'update method'), blank=True, max_length=1,\n                                      choices=UPDATE_METHODS, db_index=True, default='W')\n    user_agent = ValidXMLCharField(_(u'user agent'), blank=True, max_length=200, default='')\n    uuid = ValidXMLCharField(_(u'uuid'), blank=True, max_length=40, default='', db_index=True,\n                             help_text=_(u'Universally unique ID set by creating user agent'))\n    notes = ValidXMLTextField(verbose_name=_(u\"Notes and comments\"), blank=True, default='')\n\n    # Indicator updates\n    indicator_period = models.ForeignKey('IndicatorPeriod', related_name='updates',\n                                         verbose_name=_(u'indicator period'), blank=True, null=True)\n    period_update = models.DecimalField(_(u'period update'), blank=True, null=True, max_digits=14,\n                                        decimal_places=2)\n\n    class Meta:\n        app_label = 'rsr'\n        get_latest_by = \"created_at\"\n        verbose_name = _(u'project update')\n        verbose_name_plural = _(u'project updates')\n        ordering = ['-id', ]\n\n    def save(self, *args, **kwargs):\n        if self.indicator_period and self.period_update:\n            if not self.pk:\n                # Newly created update to indicator period, update the actual value.\n                self.indicator_period.update_actual_value(self.period_update)\n\n            else:\n                # Update to already existing indicator period, check if values have been changed.\n                orig_update = ProjectUpdate.objects.get(pk=self.pk)\n                if orig_update.indicator_period != self.indicator_period:\n                    # Indicator period has changed. Substract value from old period, and add new\n                    # value to new period.\n                    try:\n                        orig_update.update_actual_value(Decimal(orig_update.period_update) * -1)\n                    except (InvalidOperation, TypeError):\n                        pass\n                    self.indicator_period.update_actual_value(self.period_update)\n\n                elif orig_update.period_update != self.period_update:\n                    # Indicator value has changed. Add the difference to it.\n                    try:\n                        self.indicator_period.update_actual_value(\n                            Decimal(self.period_update) - Decimal(orig_update.period_update)\n                        )\n                    except (InvalidOperation, TypeError):\n                        self.indicator_period.update_actual_value(self.period_update)\n\n        super(ProjectUpdate, self).save(*args, **kwargs)\n\n    def delete(self, *args, **kwargs):\n        if self.indicator_period and self.period_update:\n            # Subsctract the value of the update from the actual value of the indicator period\n            if ProjectUpdate.objects.filter(indicator_period=self.indicator_period).\\\n                    exclude(pk=self.pk).exists():\n                try:\n                    self.indicator_period.update_actual_value(\n                        Decimal(self.period_update) * -1\n                    )\n                except (InvalidOperation, TypeError):\n                    pass\n            else:\n                # There's no other updates for this indicator period, remove actual value\n                self.indicator_period.actual_value = ''\n                self.indicator_period.save()\n        super(ProjectUpdate, self).delete(*args, **kwargs)\n\n    def clean(self):\n        if hasattr(self, 'project') and hasattr(self, 'indicator_period') and \\\n                hasattr(self, 'period_update'):\n            validation_errors = {}\n\n            # Don't allow an indicator period that belongs to a different project\n            if self.project and self.indicator_period:\n                if not self.indicator_period.indicator.result.project == self.project:\n                    validation_errors['indicator_period'] = u'%s' % _(\n                        u'Indicator period must be part of the same project'\n                    )\n\n            # Don't allow an indicator update to a non-Impact project\n            if self.indicator_period and self.period_update and not self.project.is_impact_project:\n                validation_errors['project'] = u'%s' % _(\n                    u'Project must be an Impact project to place indicator updates to it'\n                )\n\n            if validation_errors:\n                raise ValidationError(validation_errors)\n\n    def img(self, value=''):\n        try:\n            return self.photo.thumbnail_tag\n        except:\n            return value\n    img.allow_tags = True\n\n    def edit_window_has_expired(self):\n        \"\"\"Determine whether or not update timeout window has expired.\n        The timeout is controlled by settings.PROJECT_UPDATE_TIMEOUT and\n        defaults to 30 minutes.\n        \"\"\"\n        return (datetime.now() - self.created_at) > self.edit_timeout\n\n    @property\n    def expires_at(self):\n        return to_gmt(self.created_at + self.edit_timeout)\n\n    @property\n    def edit_timeout(self):\n        timeout_minutes = getattr(settings, 'PROJECT_UPDATE_TIMEOUT', 30)\n        return timedelta(minutes=timeout_minutes)\n\n    @property\n    def edit_time_remaining(self):\n        return self.edit_timeout - self.created_at\n\n    @property\n    def time_gmt(self):\n        return to_gmt(self.created_at)\n\n    @property\n    def time_last_updated_gmt(self):\n        return to_gmt(self.last_modified_at)\n\n    @property\n    def view_count(self):\n        counter = ViewCounter.objects.get_for_object(self)\n        return counter.count or 0\n\n    @models.permalink\n    def get_absolute_url(self):\n        return 'update-main', (), {'project_id': self.project.pk, 'update_id': self.pk}\n\n    def __unicode__(self):\n        return _(u'Project update for %(project_name)s') % {'project_name': self.project.title}\n", "path": "akvo/rsr/models/project_update.py"}]}