# -*- 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 decimal import Decimal
from akvo.utils import codelist_has_value
from akvo.codelists import models
VOCABULARY_CODE_MODEL_MAP = {
'1': models.Sector,
'2': models.SectorCategory,
'7': models.UNSDGGoals,
'8': models.UNSDGTargets,
}
[docs]def has_invalid_vocabulary_code(sector):
return (
sector.sector_code
and sector.vocabulary in VOCABULARY_CODE_MODEL_MAP.keys()
and not codelist_has_value(VOCABULARY_CODE_MODEL_MAP[sector.vocabulary], sector.sector_code)
)
[docs]def sectors(project):
"""
Check if sectors are present, either on project or transaction level, but not both.
If on transaction level, all transactions must have a sector.
Per sector vocabulary on project level, the percentages of the sectors should add up to 100%.
On transaction level, each sector vocabulary should only occur once per transaction.
:param project: Project object
:return: All checks passed boolean, [Check results]
"""
checks = []
all_checks_passed = True
if project.sectors.all():
for transaction in project.transactions.all():
if transaction.sectors.all():
all_checks_passed = False
checks.append(('error', 'sectors present both on project and transaction level'))
if all_checks_passed:
sectors_dict = {}
for sector in project.sectors.all():
try:
sectors_dict[sector.vocabulary or '1'].append(sector.percentage)
except KeyError:
sectors_dict[sector.vocabulary or '1'] = [sector.percentage]
for voc_key in sectors_dict:
if len(sectors_dict[voc_key]) > 1:
voc_percentage = 0
for percentage in sectors_dict[voc_key]:
try:
voc_percentage += Decimal(percentage)
except (ValueError, TypeError):
all_checks_passed = False
checks.append(('error', 'multiple sectors with vocabulary \'%s\' '
'specified, but not all have a percentage' %
str(voc_key)))
if voc_percentage == 100:
checks.append(('success', 'sector percentages for vocabulary \'%s\' '
'add up to 100' % str(voc_key)))
else:
all_checks_passed = False
checks.append(('error', 'sector percentages for vocabulary \'%s\' '
'do not add up to 100' % str(voc_key)))
sectors_by_vocabulary = dict()
for sector in project.sectors.all():
sectors_by_vocabulary.setdefault(sector.vocabulary, []).append(sector)
if not sector.sector_code:
all_checks_passed = False
checks.append(('error', 'sector (id: %s) is missing sector code' %
str(sector.pk)))
if has_invalid_vocabulary_code(sector):
all_checks_passed = False
checks.append(('error', 'sector (id: %s) has invalid sector code' % str(sector.pk)))
if sector.vocabulary in ['98', '99'] and not sector.vocabulary_uri:
checks.append(('warning', 'sector (id: %s) with vocabulary 98 or 99 (reporting '
'organisation) has no vocabulary URI specified' %
str(sector.pk)))
for grouped_sectors in sectors_by_vocabulary.values():
if len(grouped_sectors) > 1:
continue
single_sector_in_vocabulary = grouped_sectors[0]
if not single_sector_in_vocabulary.percentage or single_sector_in_vocabulary.percentage == 100:
continue
all_checks_passed = False
checks.append(('error', 'sector "%s" declared only once, the percentage must either be omitted or set to 100'
% single_sector_in_vocabulary.iati_vocabulary().name))
elif not project.transactions.all():
all_checks_passed = False
checks.append(('error', 'no sectors present on project or transaction level'))
else:
for transaction in project.transactions.all():
if not transaction.sectors.all():
all_checks_passed = False
checks.append(('error', 'no sectors on project level or transaction (id: %s) '
'missing sector' % str(transaction.pk)))
else:
sectors_vocs = []
for sector in transaction.sectors.all():
if not sector.code:
all_checks_passed = False
checks.append(('error', 'transaction sector (id: %s) is missing code' %
str(sector.pk)))
if sector.vocabulary in ['98', '99'] and not sector.vocabulary_uri:
checks.append(('warning', 'sector (id: %s) with vocabulary 98 or 99 '
'(reporting organisation) has no vocabulary '
'URI specified' % str(sector.pk)))
voc = sector.vocabulary or '1'
if voc in sectors_vocs:
all_checks_passed = False
checks.append(('error', 'multiple sectors with same vocabulary specified '
'for transaction (id: %s)' % str(transaction.pk)))
else:
sectors_vocs.append(voc)
if all_checks_passed:
checks.append(('success', 'sectors specified on one level (project or transaction)'))
return all_checks_passed, checks