# -*- coding: utf-8 -*-
# Akvo RSR is covered by the GNU Affero General Public License.
# See more details in the license.txt file located at the root folder of the Akvo RSR module.
# For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >.
from akvo.iati.exports.iati_export import IatiXML
from akvo.rsr.fields import ValidXMLCharField
from akvo.rsr.mixins import TimestampsMixin
from datetime import datetime
from django.db import models, transaction
from django.conf import settings
from django.utils.translation import gettext_lazy as _
[docs]def file_path(self, filename):
return 'db/organisation/%s/iati/%s' % (str(self.reporting_organisation.pk), filename)
[docs]class IatiExport(TimestampsMixin):
STATUS_PENDING = 1
STATUS_IN_PROGRESS = 2
STATUS_COMPLETED = 3
STATUS_CANCELLED = 4
STATUS_CODE = {
STATUS_PENDING: _('pending'),
STATUS_IN_PROGRESS: _('in progress'),
STATUS_COMPLETED: _('completed'),
STATUS_CANCELLED: _('cancelled')
}
reporting_organisation = models.ForeignKey(
'Organisation', on_delete=models.CASCADE, verbose_name=_('reporting organisation'), related_name='iati_exports'
)
user = models.ForeignKey(
settings.AUTH_USER_MODEL, on_delete=models.CASCADE, verbose_name=_('user'), related_name='iati_exports'
)
projects = models.ManyToManyField('Project', verbose_name=_('projects'))
version = ValidXMLCharField(_('version'), max_length=4, default='2.03')
status = models.PositiveSmallIntegerField(_('status'), default=STATUS_PENDING)
iati_file = models.FileField(_('IATI file'), blank=True, upload_to=file_path)
latest = models.BooleanField(_('latest'), default=False)
class Meta:
app_label = 'rsr'
verbose_name = _('IATI export')
verbose_name_plural = _('IATI exports')
ordering = ('id',)
def __str__(self):
if self.reporting_organisation and self.reporting_organisation.name:
return '%s %s' % (_('IATI export for'), self.reporting_organisation.name)
else:
return '%s' % _('IATI export for unknown organisation')
@property
def is_latest(self):
return self.latest
@is_latest.setter
def is_latest(self, latest):
if not latest:
self.latest = False
self.save(update_fields=['latest'])
return
with transaction.atomic():
# Set all other exports to not be latest
latest_exports = IatiExport.objects.filter(
latest=True, reporting_organisation=self.reporting_organisation)
latest_exports.update(latest=False)
# Set current export to be latest
self.latest = True
self.save(update_fields=['latest'])
[docs] def show_status(self):
if self.status not in self.STATUS_CODE:
return _('unknown status')
else:
return self.STATUS_CODE[self.status].title()
[docs] def update_status(self, status_code):
"""
Update the status of this IATI export.
:param status_code; Integer in self.STATUS_CODE keys
"""
self.status = status_code
self.save(update_fields=['status'])
[docs] def update_iati_file(self, iati_file):
"""
Update the IATI file of this IATI export.
:param iati_file; File object
"""
self.iati_file = iati_file
self.save(update_fields=['iati_file'])
[docs] def create_iati_file(self):
"""
Create an IATI XML file.
"""
self.update_status(self.STATUS_IN_PROGRESS)
# Retrieve all projects
projects = self.projects.all()
if projects:
try:
# Generate and save the IATI file
iati_xml = IatiXML(projects, self.version, self)
self.update_iati_file(iati_xml.save_file(
str(self.reporting_organisation.pk),
datetime.utcnow().strftime("%Y%m%d-%H%M%S") + '.xml')
)
self.update_status(self.STATUS_COMPLETED)
self.is_latest = True
except Exception:
self.update_status(self.STATUS_CANCELLED)
else:
self.update_status(self.STATUS_CANCELLED)
[docs] def processed_projects(self):
"""
Find the number of processed projects of this IATI export. Generally, for completed
exports, this number will be the same as the number of total projects.
"""
return self.iati_activity_exports.filter(status=self.STATUS_IN_PROGRESS).count()