예제 #1
0
class RecipientRegion(models.Model):
    project = models.ForeignKey(
        'Project', verbose_name=_(u'project'), related_name='recipient_regions'
    )
    region = ValidXMLCharField(
        _(u'region'), blank=True, max_length=3, choices=codelist_choices(REGION)
    )
    region_vocabulary = ValidXMLCharField(
        _(u'region vocabulary'), blank=True, max_length=1,
        choices=codelist_choices(REGION_VOCABULARY)
    )
    percentage = models.DecimalField(
        _(u'percentage'), blank=True, null=True, max_digits=4, decimal_places=1,
        validators=[MaxValueValidator(100), MinValueValidator(0)]
    )
    text = ValidXMLCharField(
        _(u'region description'), blank=True, max_length=50, help_text=_(u'(max 50 characters)')
    )

    def iati_region(self):
        return codelist_value(Region, self, 'region')

    def iati_vocabulary(self):
        return codelist_value(RegionVocabulary, self, 'region_vocabulary')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'recipient region')
        verbose_name_plural = _(u'recipient regions')
예제 #2
0
class PlannedDisbursement(models.Model):
    project = models.ForeignKey('Project',
                                verbose_name=_(u'project'),
                                related_name='planned_disbursements')
    value = models.DecimalField(_(u'value'),
                                blank=True,
                                max_digits=10,
                                decimal_places=2)
    value_date = models.DateField(_(u'value date'), null=True, blank=True)
    currency = ValidXMLCharField(_(u'currency'),
                                 blank=True,
                                 max_length=3,
                                 choices=codelist_choices(CURRENCY))
    updated = models.DateField(_(u'updated'), null=True, blank=True)
    period_start = models.DateField(_(u'period start'), null=True, blank=True)
    period_end = models.DateField(_(u'period end'), null=True, blank=True)
    type = ValidXMLCharField(_(u'type'),
                             blank=True,
                             max_length=1,
                             choices=codelist_choices(BUDGET_TYPE))

    def __unicode__(self):
        return self.value

    def iati_currency(self):
        return codelist_value(Currency, self, 'currency')

    def iati_type(self):
        return codelist_value(BudgetType, self, 'type')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'planned disbursement')
        verbose_name_plural = _(u'planned disbursements')
예제 #3
0
class HumanitarianScope(models.Model):
    project = models.ForeignKey('Project', verbose_name=_('project'),
                                related_name='humanitarian_scopes')
    code = ValidXMLCharField(
        _('humanitarian scope code'), blank=True, max_length=25,
        help_text=_('A code for the event or action from the vocabulary specified. More '
                    'information on the vocabularies can be found here: '
                    '<a href="http://glidenumber.net/glide/public/search/search.jsp" '
                    'target="_blank">Glide</a> and '
                    '<a href="http://fts.unocha.org/docs/IATICodelist_HS2-1.csv" '
                    'target="_blank">Humanitarian plan</a>.'))
    type = ValidXMLCharField(
        _('humanitarian scope type'), blank=True, max_length=1,
        choices=codelist_choices(HUMANITARIAN_SCOPE_TYPE),
        help_text=_('The type of event or action being classified. See the '
                    '<a href="http://iatistandard.org/202/codelists/HumanitarianScopeType/" '
                    'target="_blank">IATI codelist</a>.'))
    vocabulary = ValidXMLCharField(
        _('humanitarian scope vocabulary'), blank=True, max_length=3,
        choices=codelist_choices(HUMANITARIAN_SCOPE_VOCABULARY),
        help_text=_('A recognised vocabulary of terms classifying the event or action. See the '
                    '<a href="http://iatistandard.org/202/codelists/HumanitarianScopeVocabulary/" '
                    'target="_blank">IATI codelist</a>.'))
    vocabulary_uri = ValidXMLCharField(
        _('humanitarian scope vocabulary URI'), blank=True, max_length=1000,
        help_text=_('If the vocabulary is 99 (reporting organisation), the URI where this '
                    'internal vocabulary is defined.'))
    text = ValidXMLCharField(_('humanitarian scope description'), blank=True, max_length=1000,
                             help_text=_('Optionally enter a description.'))

    class Meta:
        app_label = 'rsr'
        verbose_name = _('humanitarian scope')
        verbose_name_plural = _('humanitarian scopes')
        ordering = ('pk',)

    def __str__(self):
        if self.text:
            return self.text
        elif self.code:
            return self.code
        else:
            return ''

    def iati_type(self):
        return codelist_value(HumanitarianScopeType, self, 'type')

    def iati_type_unicode(self):
        return str(self.iati_type())

    def iati_vocabulary(self):
        return codelist_value(HumanitarianScopeVocabulary, self, 'vocabulary')

    def iati_vocabulary_unicode(self):
        return str(self.iati_vocabulary())
예제 #4
0
 def test_codelist_choices_false(self):
     """
     Test calling codelist_choices(<codelist>, False)
     """
     # snippet of FINANCE_TYPE codelist
     codelist_1 = (
         ("code", "name", "description"),
         ("1", "Global", "The activity scope is global"),
         ("2", "Regional", "The activity scope is a supranational region"),
         ("3", "Multi-national",
          "The activity scope covers multiple countries, that don't constitute a region"),
         ("4", "National", "The activity scope covers one country"),
     )
     choices_1 = [
         ("1", "Global",),
         ("2", "Regional",),
         ("3", "Multi-national",),
         ("4", "National",),
     ]
     codelist_2 = (
         ("category", "code", "name"),
         ("100", "110", "Standard grant"),
         ("100", "111", "Subsidies to national private investors"),
         ("100", "210", "Interest subsidy"),
         ("200", "211", "Interest subsidy to national private exporters"),
     )
     choices_2 = [
         ("110", "Standard grant"),
         ("111", "Subsidies to national private investors"),
         ("210", "Interest subsidy"),
         ("211", "Interest subsidy to national private exporters"),
     ]
     codelist_3 = (
         ("category", "code"),
         ("application", "application/1d-interleaved-parityfec"),
         ("application", "application/3gpdash-qoe-report+xml"),
         ("application", "application/3gpp-ims+xml"),
         ("application", "application/A2L"),
     )
     choices_with_code_3 = [
         ("application/1d-interleaved-parityfec", "application/1d-interleaved-parityfec"),
         ("application/3gpdash-qoe-report+xml", "application/3gpdash-qoe-report+xml"),
         ("application/3gpp-ims+xml", "application/3gpp-ims+xml"),
         ("application/A2L", "application/A2L"),
     ]
     generated_choices_1 = codelist_choices(codelist_1, False)
     self.assertEqual(choices_1, generated_choices_1)
     generated_choices_2 = codelist_choices(codelist_2, False)
     self.assertEqual(choices_2, generated_choices_2)
     generated_choices_with_code_3 = codelist_choices(codelist_3)
     self.assertEqual(choices_with_code_3, generated_choices_with_code_3)
예제 #5
0
 def test_codelist_choices_true(self):
     """
     Test calling codelist_choices(<codelist>, True)
     """
     # snippet of FINANCE_TYPE codelist
     codelist_1 = (
         (u"code", u"name", u"description"),
         (u"1", u"Global", u"The activity scope is global"),
         (u"2", u"Regional",
          u"The activity scope is a supranational region"),
         (u"3", u"Multi-national",
          u"The activity scope covers multiple countries, that don't constitute a region"
          ),
         (u"4", u"National", u"The activity scope covers one country"),
     )
     choices_with_code_1 = [
         (
             u"1",
             u"1 - Global",
         ),
         (
             u"2",
             u"2 - Regional",
         ),
         (
             u"3",
             u"3 - Multi-national",
         ),
         (
             u"4",
             u"4 - National",
         ),
     ]
     codelist_2 = (
         (u"category", u"code", u"name"),
         (u"100", u"110", u"Standard grant"),
         (u"100", u"111", u"Subsidies to national private investors"),
         (u"100", u"210", u"Interest subsidy"),
         (u"200", u"211",
          u"Interest subsidy to national private exporters"),
     )
     choices_with_code_2 = [
         (u"110", u"110 - Standard grant"),
         (u"111", u"111 - Subsidies to national private investors"),
         (u"210", u"210 - Interest subsidy"),
         (u"211", u"211 - Interest subsidy to national private exporters"),
     ]
     generated_choices_with_code_1 = codelist_choices(codelist_1)
     self.assertEqual(choices_with_code_1, generated_choices_with_code_1)
     generated_choices_with_code_2 = codelist_choices(codelist_2)
     self.assertEqual(choices_with_code_2, generated_choices_with_code_2)
예제 #6
0
class OrganisationRegionBudget(OrganisationBudget):
    organisation = models.ForeignKey('Organisation',
                                     on_delete=models.CASCADE,
                                     verbose_name=_('organisation'),
                                     related_name='recipient_region_budgets')
    region = ValidXMLCharField(
        _('recipient region'),
        blank=True,
        max_length=25,
        choices=codelist_choices(REGION),
        help_text=_(
            'This identifies the region which concerns the organisation budget.'
        ))
    region_vocabulary = ValidXMLCharField(
        _('vocabulary'),
        blank=True,
        max_length=2,
        choices=codelist_choices(REGION_VOCABULARY),
        help_text=_(
            'The vocabulary from which the region code is drawn. If it is not present 1 – '
            '\'OECD DAC\' is assumed.'))
    region_vocabulary_uri = ValidXMLCharField(
        _('vocabulary URI'),
        blank=True,
        max_length=1000,
        help_text=_(
            'If the vocabulary is 99 (reporting organisation), the URI where this '
            'internal vocabulary is defined.'))
    text = ValidXMLCharField(
        _('description'),
        blank=True,
        max_length=100,
        help_text=_('Optionally enter a short description.'))

    class Meta:
        app_label = 'rsr'
        verbose_name = _('organisation recipient region budget')
        verbose_name_plural = _('organisation recipient region budgets')

    def iati_region(self):
        return codelist_value(Region, self, 'region')

    def iati_region_unicode(self):
        return str(self.iati_region())

    def iati_region_vocabulary(self):
        return codelist_value(RegionVocabulary, self, 'region_vocabulary')

    def iati_region_vocabulary_unicode(self):
        return str(self.iati_region_vocabulary())
예제 #7
0
class TransactionSector(models.Model):
    project = models.ForeignKey('Transaction',
                                verbose_name=_(u'transaction'),
                                related_name='sectors')
    code = ValidXMLCharField(_(u'sector'), blank=True, max_length=5)
    text = ValidXMLCharField(_(u'description'),
                             blank=True,
                             max_length=100,
                             help_text=_(u'(max 100 characters)'))
    vocabulary = ValidXMLCharField(_(u'vocabulary'),
                                   blank=True,
                                   max_length=5,
                                   choices=codelist_choices(SECTOR_VOCABULARY))

    def iati_sector(self):
        if self.code and (self.vocabulary == '1' or self.vocabulary == 'DAC'):
            return codelist_value(Sector, self, 'code')
        elif self.code and (self.vocabulary == '2'
                            or self.vocabulary == 'DAC-3'):
            return codelist_value(SectorCategory, self, 'code')
        else:
            return self.code

    def iati_vocabulary(self):
        return codelist_value(SectorVocabulary, self, 'vocabulary')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'transaction sector')
        verbose_name_plural = _(u'transaction sectors')
        unique_together = ('project', 'vocabulary')
예제 #8
0
class CrsAddOtherFlag(models.Model):
    """
    Other flag of CRS++ reporting.
    """
    crs = models.ForeignKey('CrsAdd', verbose_name=u'crs', related_name='other_flags')
    code = ValidXMLCharField(
        _(u'code'), max_length=1, choices=codelist_choices(C_R_S_ADD_OTHER_FLAGS),
        help_text=_(u'An IATI code describing the equivalent CRS++ columns. See the <a '
                    u'href="http://iatistandard.org/202/codelists/CRSAddOtherFlags/" '
                    u'target="_blank">IATI codelist</a>.')
    )
    significance = models.NullBooleanField(
        _(u'significance'), blank=True, help_text=_(u'Indicate whether the flag applies or not.')
    )

    def __unicode__(self):
        if self.code:
            try:
                return self.iati_code().name
            except AttributeError:
                return self.iati_code()
        else:
            return u'%s' % _(u'No other flag code specified')

    def iati_code(self):
        return codelist_value(CRSAddOtherFlags, self, 'code')

    def iati_code_unicode(self):
        return str(self.iati_code())

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'CRS other flag')
        verbose_name_plural = _(u'CRS other flags')
예제 #9
0
class FssForecast(models.Model):
    """
    Forecast items for an OECD DAC Forward Spending Survey item.
    """
    fss = models.ForeignKey('Fss',
                            verbose_name=_(u'fss'),
                            related_name='forecasts')
    year = models.PositiveIntegerField(_(u'year'),
                                       blank=True,
                                       null=True,
                                       max_length=4)
    value_date = models.DateField(_(u'value date'), blank=True, null=True)
    currency = ValidXMLCharField(_(u'currency'),
                                 blank=True,
                                 max_length=3,
                                 choices=codelist_choices(CURRENCY))
    value = models.DecimalField(_(u'interest received'),
                                max_digits=10,
                                decimal_places=2,
                                blank=True,
                                null=True)

    def iati_currency(self):
        return codelist_value(Currency, self, 'loan_status_currency')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'FSS forecast')
        verbose_name_plural = _(u'FSS forecasts')
예제 #10
0
class RelatedProject(models.Model):
    project = models.ForeignKey('Project', related_name='related_projects')
    related_project = models.ForeignKey('Project',
                                        related_name='related_to_projects',
                                        null=True,
                                        blank=True,
                                        on_delete=models.SET_NULL)
    related_iati_id = ValidXMLCharField(
        _(u'related project IATI identifier'),
        max_length=100,
        blank=True,
        help_text=_(
            u'The IATI Identifier for the related project.<br>'
            u'Fill this in if the related project does not exist in RSR'))
    relation = ValidXMLCharField(
        _(u'relation'),
        max_length=1,
        choices=codelist_choices(RELATED_ACTIVITY_TYPE),
        help_text=_(
            u'The relation between a project and related project. '
            u'(E.g. select the \'Parent\' relation when the selected project here is '
            u'the parent of this project).'))

    def iati_relation(self):
        return codelist_value(RelatedActivityType, self, 'relation')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'related project')
        verbose_name_plural = _(u'related projects')
        ordering = [
            'project',
        ]
예제 #11
0
class ProjectDocumentCategory(models.Model):
    document = models.ForeignKey(ProjectDocument, on_delete=models.CASCADE, related_name='categories',
                                 verbose_name=_('document'))
    category = ValidXMLCharField(_('document category'), max_length=3, blank=True,
                                 choices=codelist_choices(DOCUMENT_CATEGORY),
                                 help_text=_('The description of the type of content contained '
                                             'within the document.'))

    class Meta:
        app_label = 'rsr'
        verbose_name = _('project document category')
        verbose_name_plural = _('project document categories')
        ordering = ['-id', ]

    def __str__(self):
        if self.category:
            try:
                return self.iati_category().name
            except AttributeError:
                return self.iati_category()
        else:
            return '%s' % _('No category specified')

    def iati_category(self):
        return codelist_value(DocumentCategory, self, 'category')

    def iati_category_unicode(self):
        return str(self.iati_category())
예제 #12
0
class CountryBudgetItem(models.Model):
    project = models.ForeignKey('Project',
                                verbose_name=_(u'project'),
                                related_name='country_budget_items')
    code = ValidXMLCharField(_(u'budget item'),
                             max_length=6,
                             blank=True,
                             choices=codelist_choices(BUDGET_IDENTIFIER))
    description = ValidXMLCharField(_(u'description'),
                                    max_length=100,
                                    blank=True,
                                    help_text=_(u'(max 100 characters)'))
    percentage = models.DecimalField(
        _(u'percentage'),
        blank=True,
        null=True,
        max_digits=4,
        decimal_places=1,
        validators=[MaxValueValidator(100),
                    MinValueValidator(0)])

    def iati_code(self):
        return codelist_value(BudgetIdentifier, self, 'code')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'country budget item')
        verbose_name_plural = _(u'country budget items')
예제 #13
0
class OrganisationDocumentCountry(models.Model):
    document = models.ForeignKey(OrganisationDocument, related_name='countries',
                                 verbose_name=_('document'))
    country = ValidXMLCharField(
        _('recipient country'), blank=True, max_length=2, choices=codelist_choices(COUNTRY, show_code=False),
        help_text=_('This identifies the country which concerns the organisation document.')
    )
    text = ValidXMLCharField(
        _('description'), blank=True, max_length=100,
        help_text=_('Optionally enter a short description.')
    )

    class Meta:
        app_label = 'rsr'
        verbose_name = _('document country')
        verbose_name_plural = _('document countries')
        ordering = ['-id', ]

    def __str__(self):
        if self.country:
            try:
                return self.iati_country().name
            except AttributeError:
                return self.iati_country()
        else:
            return '%s' % _('No country specified')

    def iati_country(self):
        return codelist_value(Country, self, 'country')

    def iati_country_unicode(self):
        return str(self.iati_country())
예제 #14
0
class OrganisationCountryBudget(OrganisationBudget):
    organisation = models.ForeignKey('Organisation',
                                     verbose_name=_('organisation'),
                                     related_name='recipient_country_budgets')
    country = ValidXMLCharField(
        _('recipient country'),
        blank=True,
        max_length=2,
        choices=codelist_choices(COUNTRY, show_code=False),
        help_text=
        _('This identifies the country which concerns the organisation budget.'
          ))
    text = ValidXMLCharField(
        _('description'),
        blank=True,
        max_length=100,
        help_text=_('Optionally enter a short description.'))

    class Meta:
        app_label = 'rsr'
        verbose_name = _('organisation recipient country budget')
        verbose_name_plural = _('organisation recipient country budgets')

    def iati_country(self):
        return codelist_value(Country, self, 'country')

    def iati_country_unicode(self):
        return str(self.iati_country())
예제 #15
0
파일: country.py 프로젝트: ronna/akvo-rsr
class RecipientCountry(models.Model):
    project = models.ForeignKey('Project',
                                on_delete=models.CASCADE,
                                verbose_name=_('project'),
                                related_name='recipient_countries')
    country = ValidXMLCharField(
        _('recipient country'),
        blank=True,
        max_length=2,
        choices=codelist_choices(COUNTRY, show_code=False),
        help_text=_('The country that benefits from the project.'))
    percentage = models.DecimalField(
        _('recipient country percentage'),
        blank=True,
        null=True,
        max_digits=4,
        decimal_places=1,
        validators=[MaxValueValidator(100),
                    MinValueValidator(0)],
        help_text=
        _('The percentage of total commitments or total activity budget allocated to '
          'this country. Content must be a positive decimal number between 0 and 100, '
          'with no percentage sign. Percentages for all reported countries and regions '
          'MUST add up to 100%. Use a period to denote decimals.'))
    text = ValidXMLCharField(
        _('recipient country description'),
        blank=True,
        max_length=50,
        help_text=
        _('Enter additional information about the recipient country, if necessary.'
          ))

    def __str__(self):
        if self.country:
            try:
                country_unicode = self.iati_country().name
            except (AttributeError, codelist_models.Country.DoesNotExist):
                country_unicode = self.country
        else:
            country_unicode = '%s' % _('No country specified')

        if self.percentage:
            country_unicode += ' (%s%%)' % str(self.percentage)

        return country_unicode

    def iati_country(self):
        return codelist_value(codelist_models.Country, self, 'country')

    def iati_country_unicode(self):
        return str(self.iati_country())

    class Meta:
        app_label = 'rsr'
        verbose_name = _('recipient country')
        verbose_name_plural = _('recipient countries')
        ordering = ('-percentage', 'country')
예제 #16
0
def update_directory(request):
    """REST view for the update directory."""

    # Fetch updates based on whether we are on Akvo site or RSR main site
    page = request.rsr_page
    all_updates = _all_updates() if not page else page.updates()

    # Filter updates based on query parameters
    filter_, text_filter = _create_filters_query(request)
    updates = all_updates.filter(
        filter_).distinct() if filter_ is not None else all_updates

    updates_text_filtered = updates.filter(
        text_filter) if text_filter is not None else updates
    if updates_text_filtered.exists():
        updates = updates_text_filtered

    # Get the relevant data for typeaheads based on filtered updates (minus
    # text filtering, if no updates were found)
    locations = [{
        'id': choice[0],
        'name': choice[1]
    } for choice in location_choices(updates)]
    project_ids = updates.values_list('project__id', flat=True)
    projects = Project.objects.filter(id__in=project_ids)
    organisations = projects.all_partners().values('id', 'name', 'long_name')

    # FIXME: Currently only vocabulary 2 is supported (as was the case with
    # static filters). This could be extended to other vocabularies, in future.
    valid_sectors = dict(codelist_choices(SECTOR_CATEGORY))
    sectors = projects.sectors().filter(
        vocabulary='2',
        sector_code__in=valid_sectors).values('sector_code').distinct()

    count = updates_text_filtered.count()
    display_updates = get_qs_elements_for_page(updates_text_filtered, request,
                                               count)
    display_updates = display_updates.select_related(
        'project',
        'project__primary_location',
        'project__primary_organisation',
        'user',
    ).prefetch_related('project__partners', 'project__sectors', 'locations',
                       'locations__country')

    response = {
        'project_count': count,
        'projects': ProjectUpdateDirectorySerializer(display_updates,
                                                     many=True).data,
        'organisation': TypeaheadOrganisationSerializer(organisations,
                                                        many=True).data,
        'location': locations,
        'sector': TypeaheadSectorSerializer(sectors, many=True).data,
        'page_size_default': settings.PROJECT_DIRECTORY_PAGE_SIZES[0],
    }
    return Response(response)
예제 #17
0
def update_directory(request):
    """REST view for the update directory."""

    # Fetch updates based on whether we are on Akvo site or RSR main site
    page = request.rsr_page
    all_updates = _all_updates() if not page else _page_updates(page)

    # Filter updates based on query parameters
    filter_, text_filter = _create_filters_query(request)
    updates = all_updates.filter(filter_).distinct() if filter_ is not None else all_updates

    updates_text_filtered = updates.filter(text_filter) if text_filter is not None else updates
    if updates_text_filtered.exists():
        updates = updates_text_filtered

    # Get the relevant data for typeaheads based on filtered updates (minus
    # text filtering, if no updates were found)
    locations = [
        {'id': choice[0], 'name': choice[1]}
        for choice in location_choices(updates)
    ]
    project_ids = updates.values_list('project__id', flat=True)
    projects = Project.objects.filter(id__in=project_ids)
    organisations = projects.all_partners().values('id', 'name', 'long_name')

    # FIXME: Currently only vocabulary 2 is supported (as was the case with
    # static filters). This could be extended to other vocabularies, in future.
    valid_sectors = dict(codelist_choices(SECTOR_CATEGORY))
    sectors = projects.sectors().filter(
        vocabulary='2', sector_code__in=valid_sectors
    ).values('sector_code').distinct()

    display_updates = get_qs_elements_for_page(updates_text_filtered, request)
    count = updates_text_filtered.count()
    display_updates = display_updates.select_related(
        'project',
        'project__primary_location',
        'project__primary_organisation',
        'user',
    ).prefetch_related(
        'project__partners',
        'project__sectors',
        'locations',
        'locations__country'
    )

    response = {
        'project_count': count,
        'projects': ProjectUpdateDirectorySerializer(display_updates, many=True).data,
        'organisation': TypeaheadOrganisationSerializer(organisations, many=True).data,
        'location': locations,
        'sector': TypeaheadSectorSerializer(sectors, many=True).data,
        'page_size_default': settings.PROJECT_DIRECTORY_PAGE_SIZES[0],
    }
    return Response(response)
예제 #18
0
class ProjectContact(models.Model):
    project = models.ForeignKey('Project', on_delete=models.CASCADE, verbose_name=_('project'), related_name='contacts')
    type = ValidXMLCharField(
        _('contact type'), blank=True, max_length=1, choices=codelist_choices(CONTACT_TYPE),
        help_text=_('What types of enquiries this contact person is best-placed to handle.')
    )
    person_name = ValidXMLCharField(
        _('contact name'), blank=True, max_length=100,
        help_text=_('Please enter the name of the contact person for this project.')
    )
    email = models.EmailField(_('contact email'), blank=True)
    job_title = ValidXMLCharField(
        _('job title'), max_length=100, blank=True,
        help_text=_('Job title of the contact person.')
    )
    organisation = ValidXMLCharField(
        _('contact organisation'), blank=True, max_length=100,
        help_text=_('The organisation that the contact person works for.')
    )
    telephone = ValidXMLCharField(
        _('contact phone number'), blank=True, max_length=30,
        help_text=_('Contact number for the contact person. Avoid giving personal contact '
                    'details.')
    )
    mailing_address = ValidXMLCharField(
        _('contact address'), max_length=255, blank=True,
        help_text=_('Address of the contact person. Avoid giving personal contact details.')
    )
    state = ValidXMLCharField(_('state'), blank=True, max_length=100,
                              help_text=_('(100 characters)'))
    country = models.ForeignKey('Country', on_delete=models.CASCADE, blank=True, null=True, verbose_name=_('country'),
                                related_name='contacts')
    department = ValidXMLCharField(_('department'), blank=True, max_length=100)
    website = models.URLField(
        _('contact website'), blank=True,
        help_text=_('The contact web address, if available. The web address should start with '
                    '\'http://\' or \'https://\'.')
    )

    def iati_type(self):
        return codelist_value(ContactType, self, 'type')

    def iati_type_unicode(self):
        return str(self.iati_type())

    class Meta:
        app_label = 'rsr'
        verbose_name = _('contact')
        verbose_name_plural = _('contacts')
        ordering = ('id',)

    def __str__(self):
        return self.person_name if self.person_name else '%s' % _('No contact name specified')
예제 #19
0
class IndicatorReference(models.Model):

    project_relation = 'results__indicators__references__in'

    indicator = models.ForeignKey(Indicator,
                                  on_delete=models.CASCADE,
                                  verbose_name=_('indicator'),
                                  related_name='references')
    reference = ValidXMLCharField(
        _('reference code'),
        blank=True,
        max_length=25,
        help_text=
        _('A code for an indicator defined in the specified vocabulary specified. '
          'For more information on the indicator reference, see the '
          '<a href="http://iatistandard.org/202/activity-standard/iati-activities/'
          'iati-activity/result/indicator/reference/" target="_blank">IATI '
          'codelist</a>.'))
    vocabulary = ValidXMLCharField(
        _('reference vocabulary'),
        blank=True,
        max_length=2,
        choices=codelist_choices(INDICATOR_VOCABULARY),
        help_text=
        _('This is the code for the vocabulary used to describe the sector. Sectors '
          'should be mapped to DAC sectors to enable international comparison. '
          'For more information on the indicator reference, see the '
          '<a href="http://iatistandard.org/202/codelists/IndicatorVocabulary/" '
          'target="_blank">IATI codelist</a>.'))
    vocabulary_uri = ValidXMLCharField(
        _('reference indicator URI'),
        blank=True,
        max_length=1000,
        help_text=_(
            'If the vocabulary is 99 (reporting organisation), the URI where this '
            'internal vocabulary is defined.'))

    class Meta:
        app_label = 'rsr'
        verbose_name = _('indicator reference')
        verbose_name_plural = _('indicator references')
        ordering = ('pk', )

    def __str__(self):
        return self.reference

    def iati_vocabulary(self):
        return codelist_value(IndicatorVocabulary, self, 'vocabulary')

    def iati_vocabulary_unicode(self):
        return str(self.iati_vocabulary())
예제 #20
0
파일: fss.py 프로젝트: ronna/akvo-rsr
class FssForecast(models.Model):
    """
    Forecast items for an OECD DAC Forward Spending Survey item.
    """
    fss = models.ForeignKey('Fss',
                            on_delete=models.CASCADE,
                            verbose_name=_('fss'),
                            related_name='forecasts')
    year = models.PositiveIntegerField(
        _('year'),
        blank=True,
        null=True,
        help_text=_('The calendar year that the forward spend covers.'))
    value_date = models.DateField(
        _('value date'),
        blank=True,
        null=True,
        help_text=_(
            'Enter the specific date (DD/MM/YYYY) for the forecast value.'))
    currency = ValidXMLCharField(_('currency'),
                                 blank=True,
                                 max_length=3,
                                 choices=codelist_choices(CURRENCY))
    value = models.DecimalField(
        _('forecast value'),
        max_digits=10,
        decimal_places=2,
        blank=True,
        null=True,
        help_text=_('The forecast value for each year.'))

    def __str__(self):
        if self.value and self.currency:
            try:
                return '{0} {1}'.format(self.iati_currency().name, self.value)
            except AttributeError:
                return '{0} {1}'.format(self.iati_currency(), self.value)
        else:
            return '%s' % _('No currency or interest received specified')

    def iati_currency(self):
        return codelist_value(Currency, self, 'currency')

    def iati_currency_unicode(self):
        return str(self.iati_currency())

    class Meta:
        app_label = 'rsr'
        verbose_name = _('FSS forecast')
        verbose_name_plural = _('FSS forecasts')
        ordering = ('pk', )
예제 #21
0
파일: location.py 프로젝트: zuhdil/akvo-rsr
class OrganisationLocation(BaseLocation):
    location_target = models.ForeignKey('Organisation',
                                        related_name='locations')
    iati_country = ValidXMLCharField(
        _(u'country'),
        blank=True,
        max_length=2,
        choices=codelist_choices(COUNTRY, show_code=False),
        help_text=_(u'The country in which the organisation is located.'))

    def iati_country_value(self):
        return codelist_value(Country, self, 'iati_country')

    def iati_country_value_unicode(self):
        return unicode(self.iati_country_value())
예제 #22
0
class LineBasic(models.Model):
    currency = ValidXMLCharField(_('currency'),
                                 max_length=3,
                                 blank=True,
                                 choices=codelist_choices(CURRENCY))
    value = models.DecimalField(
        _('value'),
        max_digits=20,
        decimal_places=2,
        null=True,
        blank=True,
        help_text=
        _('Enter the amount of this specific line. Use a period to denote decimals.'
          ))
    value_date = models.DateField(
        _('value date'),
        null=True,
        blank=True,
        help_text=_(
            'Enter the date (DD/MM/YYYY) to be used for determining the exchange rate for '
            'currency conversions.'))
    reference = ValidXMLCharField(
        _('reference'),
        blank=True,
        max_length=50,
        help_text=_(
            'An internal reference that describes the line in the reporting '
            'organisation\'s own system'))
    text = ValidXMLCharField(_('description'),
                             blank=True,
                             max_length=1000,
                             help_text=_('The description for this line.'))

    class Meta:
        app_label = 'rsr'
        abstract = True

    def __str__(self):
        if self.value and self.currency:
            return '%s %s' % (self.currency, '{:,}'.format(int(self.value)))
        else:
            return '%s' % _('No currency or value specified')

    def iati_currency(self):
        return codelist_value(Currency, self, 'currency')

    def iati_currency_unicode(self):
        return str(self.iati_currency())
예제 #23
0
class CountryBudgetItem(models.Model):
    project = models.ForeignKey('Project',
                                on_delete=models.CASCADE,
                                verbose_name=_('project'),
                                related_name='country_budget_items')
    code = ValidXMLCharField(
        _('country budget item'),
        max_length=10,
        blank=True,
        choices=codelist_choices(BUDGET_IDENTIFIER),
        help_text=
        _('This item encodes the alignment of activities with both the functional and '
          'administrative classifications used in the recipient country’s Chart of '
          'Accounts. This applies to both on- and off-budget activities.'))
    description = ValidXMLCharField(
        _('country budget item description'),
        max_length=100,
        blank=True,
    )
    percentage = models.DecimalField(
        _('country budget item percentage'),
        blank=True,
        null=True,
        max_digits=4,
        decimal_places=1,
        validators=[MaxValueValidator(100),
                    MinValueValidator(0)],
        help_text=
        _('If more than one identifier is reported, the percentage share must be '
          'reported and all percentages should add up to 100 percent. Use a period to '
          'denote decimals.'))

    def __str__(self):
        return self.iati_code(
        ).name if self.code else '%s' % _('No code specified')

    def iati_code(self):
        return codelist_value(BudgetIdentifier, self, 'code')

    def iati_code_unicode(self):
        return str(self.iati_code())

    class Meta:
        app_label = 'rsr'
        verbose_name = _('country budget item')
        verbose_name_plural = _('country budget items')
        ordering = ('pk', )
예제 #24
0
파일: typeahead.py 프로젝트: ronna/akvo-rsr
class TypeaheadSectorSerializer(serializers.ModelSerializer):

    id = serializers.SerializerMethodField()
    name = serializers.SerializerMethodField()

    # Lookup attribute for sector names. Not a serialized attribute.
    sectors = dict(codelist_choices(SECTOR_CATEGORY, show_code=False))

    def get_id(self, obj):
        return obj['sector_code']

    def get_name(self, obj):
        return self.sectors[obj['sector_code']]

    class Meta:
        model = Sector
        fields = ('id', 'name')
예제 #25
0
class ProjectFilter(django_filters.FilterSet):

    category = django_filters.ChoiceFilter(choices=(
        [('', _('All'))] +
        list(Category.objects.all().values_list('id', 'name', flat=False))),
                                           label=_(u'category'),
                                           name='categories__id')

    location = django_filters.ChoiceFilter(choices=M49_CODES,
                                           label=_(u'location'),
                                           action=filter_m49)

    sector = django_filters.ChoiceFilter(initial=_('All'),
                                         choices=([('', _('All'))] +
                                                  sectors()),
                                         label=_(u'sector'),
                                         name='sectors__sector_code')

    status = django_filters.ChoiceFilter(initial=_('All'),
                                         label=_(u'status'),
                                         choices=ANY_CHOICE + Project.STATUSES)

    iati_status = django_filters.ChoiceFilter(
        initial=_('All'),
        label=_(u'status'),
        choices=([('', _('All'))] + codelist_choices(ACTIVITY_STATUS, False)))

    title = django_filters.CharFilter(lookup_type='icontains',
                                      label=_(u'Search'),
                                      name='title')

    organisation = django_filters.ChoiceFilter(choices=get_orgs(),
                                               label=_(u'organisation'),
                                               name='partners__id')

    class Meta:
        model = Project
        fields = [
            'status',
            'iati_status',
            'location',
            'organisation',
            'category',
            'sector',
            'title',
        ]
예제 #26
0
class Result(models.Model):
    project = models.ForeignKey('Project',
                                verbose_name=_(u'project'),
                                related_name='results')
    title = ValidXMLCharField(
        _(u'title'),
        blank=True,
        max_length=255,
        help_text=_(
            u'Enter the title of the result for this project. (255 characters)'
        ))
    type = ValidXMLCharField(
        _(u'type'),
        blank=True,
        max_length=1,
        choices=codelist_choices(RESULT_TYPE),
        help_text=_(
            u'Select whether the result is an output, outcome or impact. '
            u'<a href="http://www.tacticalphilanthropy.com/2010/06/'
            u'outputs-outcomes-impact-oh-my/" target="_blank">'
            u'Further explanation on result types</a>'))
    aggregation_status = models.NullBooleanField(_(u'aggregation status'),
                                                 blank=True)
    description = ValidXMLCharField(
        _(u'description'),
        blank=True,
        max_length=2000,
        help_text=
        _(u'You can provide further information of the result here. (2000 characters)'
          ))

    def __unicode__(self):
        return self.title

    def iati_type(self):
        return codelist_value(ResultType, self, 'type')

    def has_info(self):
        if self.title or self.type or self.aggregation_status or self.description:
            return True
        return False

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'result')
        verbose_name_plural = _(u'results')
예제 #27
0
class AdministrativeLocation(models.Model):

    project_relation = 'locations__administratives__in'

    location = models.ForeignKey('ProjectLocation',
                                 on_delete=models.CASCADE,
                                 verbose_name=_('location'),
                                 related_name='administratives')
    code = ValidXMLCharField(
        _('administrative code'),
        blank=True,
        max_length=25,
        help_text=
        _('Coded identification of national and sub-national divisions according to '
          'recognised administrative boundary repositories. Multiple levels may be '
          'reported.'))
    vocabulary = ValidXMLCharField(
        _('administrative vocabulary'),
        blank=True,
        max_length=2,
        choices=codelist_choices(GEOGRAPHIC_VOCABULARY),
        help_text=_(
            'For reference: <a href="http://iatistandard.org/202/codelists/'
            'GeographicVocabulary/" target="_blank">http://iatistandard.org/202/codelists/'
            'GeographicVocabulary/</a>.'))

    level = models.PositiveSmallIntegerField(_('administrative level'),
                                             blank=True,
                                             null=True)

    def __str__(self):
        return str(self.code) if self.code else '%s' % _('No code specified')

    def iati_vocabulary(self):
        return codelist_value(GeographicVocabulary, self, 'vocabulary')

    def iati_vocabulary_unicode(self):
        return str(self.iati_vocabulary())

    class Meta:
        app_label = 'rsr'
        verbose_name = _('location administrative')
        verbose_name_plural = _('location administratives')
        ordering = ('pk', )
예제 #28
0
class OrganisationBudget(OrganisationFinanceBasic):
    status = ValidXMLCharField(
        _('status'),
        max_length=1,
        blank=True,
        choices=codelist_choices(BUDGET_STATUS),
        help_text=_(
            'The status explains whether the budget being reported is indicative or has '
            'been formally committed.'))

    class Meta:
        app_label = 'rsr'
        abstract = True

    def iati_status(self):
        return codelist_value(BudgetStatus, self, 'status')

    def iati_status_unicode(self):
        return str(self.iati_status())
예제 #29
0
class CrsAddOtherFlag(models.Model):
    """
    Other flag of CRS++ reporting.
    """
    crs = models.ForeignKey('CrsAdd',
                            verbose_name=u'crs',
                            related_name='other_flags')
    code = ValidXMLCharField(_(u'code'),
                             max_length=1,
                             choices=codelist_choices(C_R_S_ADD_OTHER_FLAGS))
    significance = models.NullBooleanField(_(u'significance'), blank=True)

    def iati_code(self):
        return codelist_value(CRSAddOtherFlags, self, 'code')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'CRS other flag')
        verbose_name_plural = _(u'CRS other flags')
예제 #30
0
class ProjectCondition(models.Model):
    project = models.ForeignKey('Project',
                                on_delete=models.CASCADE,
                                verbose_name=_('project'),
                                related_name='conditions')
    text = ValidXMLCharField(
        _('condition'),
        blank=True,
        max_length=100,
        help_text=
        _('The text of a specific condition attached to the Project. Organisation-wide '
          'terms and conditions that apply to all activities should not be reported '
          'here, but in either iati-organisation/document-link or '
          'iati-activity-document-link.'))
    type = ValidXMLCharField(
        _('condition type'),
        blank=True,
        max_length=1,
        choices=codelist_choices(CONDITION_TYPE),
        help_text=
        _('Condition type – e.g. policy, performance.<br/>'
          '1 - Policy: The condition attached requires a particular policy to be '
          'implemented by the recipient<br/>'
          '2 - Performance: The condition attached requires certain outputs or outcomes '
          'to be achieved by the recipient<br/>'
          '3 - Fiduciary: The condition attached requires use of certain public '
          'financial management or public accountability measures by the recipient'
          ))

    def __str__(self):
        return self.text if self.text else '%s' % _('No condition specified')

    def iati_type(self):
        return codelist_value(ConditionType, self, 'type')

    def iati_type_unicode(self):
        return str(self.iati_type())

    class Meta:
        app_label = 'rsr'
        verbose_name = _('condition')
        verbose_name_plural = _('conditions')
        ordering = ('pk', )
예제 #31
0
class ProjectCondition(models.Model):
    project = models.ForeignKey('Project',
                                verbose_name=_(u'project'),
                                related_name='conditions')
    text = ValidXMLCharField(_(u'condition'),
                             blank=True,
                             max_length=100,
                             help_text=_(u'(100 characters)'))
    type = ValidXMLCharField(_(u'condition type'),
                             blank=True,
                             max_length=1,
                             choices=codelist_choices(CONDITION_TYPE))

    def iati_type(self):
        return codelist_value(ConditionType, self, 'type')

    class Meta:
        app_label = 'rsr'
        verbose_name = _(u'condition')
        verbose_name_plural = _(u'conditions')
예제 #32
0
파일: filters.py 프로젝트: akvo/akvo-rsr
def sectors():
    sectors_list = []
    for sector in codelist_choices(SECTOR_CATEGORY):
        sectors_list.append(sector)
    return sectors_list
예제 #33
0
파일: project.py 프로젝트: akvo/akvo-rsr
def project_directory(request):
    """Return the values for various project filters.

    Based on the current filters, it returns new options for all the (other)
    filters. This is used to generate dynamic filters.

    """

    # Fetch projects based on whether we are an Akvo site or RSR main site
    page = request.rsr_page
    projects = page.projects() if page else Project.objects.all().public().published()

    # Exclude projects which don't have an image or a title
    # FIXME: This happens silently and may be confusing?
    projects = projects.exclude(Q(title='') | Q(current_image=''))

    # Filter projects based on query parameters
    filter_, text_filter = _create_filters_query(request)
    projects = projects.filter(filter_).distinct() if filter_ is not None else projects
    # NOTE: The text filter is handled differently/separately from the other filters.
    # The text filter allows users to enter free form text, which could result in no
    # projects being found for the given text. Other fields only allow selecting from
    # a list of options, and for every combination that is shown to users and
    # selectable by them, at least one project exists.
    # When no projects are returned for a given search string, if the text search is
    # not handled separately, the options for all the other filters are empty, and
    # this causes the filters to get cleared automatically. This is very weird UX.
    projects_text_filtered = (
        projects.filter(text_filter) if text_filter is not None else projects
    )
    if projects_text_filtered.exists():
        projects = projects_text_filtered

    # Pre-fetch related fields to make things faster
    projects = projects.select_related(
        'primary_location',
        'primary_organisation',
    ).prefetch_related(
        'locations',
        'locations__country',
        'recipient_countries',
        'recipient_countries__country',
    )

    # Get the relevant data for typeaheads based on filtered projects (minus
    # text filtering, if no projects were found)
    cached_locations, _ = get_cached_data(request, 'locations', None, None)
    if cached_locations is None:
        cached_locations = [
            {'id': choice[0], 'name': choice[1]}
            for choice in location_choices(projects)
        ]
        set_cached_data(request, 'locations', cached_locations)

    organisations = projects.all_partners().values('id', 'name', 'long_name')

    # FIXME: Currently only vocabulary 2 is supported (as was the case with
    # static filters). This could be extended to other vocabularies, in future.
    valid_sectors = dict(codelist_choices(SECTOR_CATEGORY))
    sectors = projects.sectors().filter(
        vocabulary='2', sector_code__in=valid_sectors
    ).values('sector_code').distinct()

    # NOTE: We use projects_text_filtered for displaying projects
    count = projects_text_filtered.count()
    display_projects = get_qs_elements_for_page(projects_text_filtered, request).select_related(
        'primary_organisation'
    )

    # NOTE: We use the _get_cached_data function to individually cache small
    # bits of data to avoid the response from never getting saved in the cache,
    # because the response is larger than the max size of data that can be
    # saved in the cache.
    cached_projects, showing_cached_projects = get_cached_data(
        request, 'projects', display_projects, ProjectDirectorySerializer
    )
    cached_organisations, _ = get_cached_data(
        request, 'organisations', organisations, TypeaheadOrganisationSerializer
    )

    response = {
        'project_count': count,
        'projects': cached_projects,
        'showing_cached_projects': showing_cached_projects,
        'organisation': cached_organisations,
        'sector': TypeaheadSectorSerializer(sectors, many=True).data,
        'location': cached_locations,
        'page_size_default': settings.PROJECT_DIRECTORY_PAGE_SIZES[0],
    }

    return Response(response)