From eb0e42c57c88ba56d9d0a85a6a21454c6d7336c0 Mon Sep 17 00:00:00 2001 From: Kasper Brandt Date: Wed, 2 Sep 2015 12:49:47 +0300 Subject: [PATCH] [#1770] Get or create project based on IATI activity ID --- akvo/iati/exports/elements/__init__.py | 86 ++++++++++ akvo/iati/exports/elements/activity_date.py | 43 +++++ akvo/iati/exports/elements/activity_scope.py | 22 +++ akvo/iati/exports/elements/activity_status.py | 31 ++++ akvo/iati/exports/elements/background.py | 26 +++ akvo/iati/exports/elements/budget.py | 48 ++++++ akvo/iati/exports/elements/capital_spend.py | 22 +++ .../exports/elements/collaboration_type.py | 22 +++ akvo/iati/exports/elements/conditions.py | 35 ++++ akvo/iati/exports/elements/contact_info.py | 64 +++++++ .../exports/elements/country_budget_items.py | 37 ++++ akvo/iati/exports/elements/crs_add.py | 91 ++++++++++ .../exports/elements/current_situation.py | 26 +++ .../iati/exports/elements/default_aid_type.py | 22 +++ .../exports/elements/default_finance_type.py | 22 +++ .../exports/elements/default_flow_type.py | 22 +++ .../exports/elements/default_tied_status.py | 22 +++ akvo/iati/exports/elements/document_link.py | 104 +++++++++++ akvo/iati/exports/elements/fss.py | 49 ++++++ akvo/iati/exports/elements/goals_overview.py | 26 +++ akvo/iati/exports/elements/iati_identifier.py | 22 +++ akvo/iati/exports/elements/legacy_data.py | 30 ++++ akvo/iati/exports/elements/location.py | 78 +++++++++ .../iati/exports/elements/other_identifier.py | 53 ++++++ .../exports/elements/participating_org.py | 50 ++++++ .../exports/elements/planned_disbursement.py | 45 +++++ akvo/iati/exports/elements/policy_marker.py | 34 ++++ akvo/iati/exports/elements/project_plan.py | 26 +++ .../exports/elements/recipient_country.py | 33 ++++ .../iati/exports/elements/recipient_region.py | 36 ++++ .../iati/exports/elements/related_activity.py | 43 +++++ akvo/iati/exports/elements/reporting_org.py | 39 +++++ akvo/iati/exports/elements/result.py | 102 +++++++++++ akvo/iati/exports/elements/sector.py | 36 ++++ akvo/iati/exports/elements/subtitle.py | 26 +++ akvo/iati/exports/elements/summary.py | 26 +++ akvo/iati/exports/elements/sustainability.py | 26 +++ akvo/iati/exports/elements/target_group.py | 26 +++ akvo/iati/exports/elements/title.py | 23 +++ akvo/iati/exports/elements/transaction.py | 161 ++++++++++++++++++ akvo/iati/imports/iati_import.py | 26 ++- akvo/iati/imports/iati_import_activity.py | 94 ++++++++++ akvo/rsr/exceptions.py | 13 ++ 43 files changed, 1864 insertions(+), 4 deletions(-) create mode 100644 akvo/iati/exports/elements/__init__.py create mode 100644 akvo/iati/exports/elements/activity_date.py create mode 100644 akvo/iati/exports/elements/activity_scope.py create mode 100644 akvo/iati/exports/elements/activity_status.py create mode 100644 akvo/iati/exports/elements/background.py create mode 100644 akvo/iati/exports/elements/budget.py create mode 100644 akvo/iati/exports/elements/capital_spend.py create mode 100644 akvo/iati/exports/elements/collaboration_type.py create mode 100644 akvo/iati/exports/elements/conditions.py create mode 100644 akvo/iati/exports/elements/contact_info.py create mode 100644 akvo/iati/exports/elements/country_budget_items.py create mode 100644 akvo/iati/exports/elements/crs_add.py create mode 100644 akvo/iati/exports/elements/current_situation.py create mode 100644 akvo/iati/exports/elements/default_aid_type.py create mode 100644 akvo/iati/exports/elements/default_finance_type.py create mode 100644 akvo/iati/exports/elements/default_flow_type.py create mode 100644 akvo/iati/exports/elements/default_tied_status.py create mode 100644 akvo/iati/exports/elements/document_link.py create mode 100644 akvo/iati/exports/elements/fss.py create mode 100644 akvo/iati/exports/elements/goals_overview.py create mode 100644 akvo/iati/exports/elements/iati_identifier.py create mode 100644 akvo/iati/exports/elements/legacy_data.py create mode 100644 akvo/iati/exports/elements/location.py create mode 100644 akvo/iati/exports/elements/other_identifier.py create mode 100644 akvo/iati/exports/elements/participating_org.py create mode 100644 akvo/iati/exports/elements/planned_disbursement.py create mode 100644 akvo/iati/exports/elements/policy_marker.py create mode 100644 akvo/iati/exports/elements/project_plan.py create mode 100644 akvo/iati/exports/elements/recipient_country.py create mode 100644 akvo/iati/exports/elements/recipient_region.py create mode 100644 akvo/iati/exports/elements/related_activity.py create mode 100644 akvo/iati/exports/elements/reporting_org.py create mode 100644 akvo/iati/exports/elements/result.py create mode 100644 akvo/iati/exports/elements/sector.py create mode 100644 akvo/iati/exports/elements/subtitle.py create mode 100644 akvo/iati/exports/elements/summary.py create mode 100644 akvo/iati/exports/elements/sustainability.py create mode 100644 akvo/iati/exports/elements/target_group.py create mode 100644 akvo/iati/exports/elements/title.py create mode 100644 akvo/iati/exports/elements/transaction.py create mode 100644 akvo/iati/imports/iati_import_activity.py create mode 100644 akvo/rsr/exceptions.py diff --git a/akvo/iati/exports/elements/__init__.py b/akvo/iati/exports/elements/__init__.py new file mode 100644 index 0000000000..4d808c3366 --- /dev/null +++ b/akvo/iati/exports/elements/__init__.py @@ -0,0 +1,86 @@ +# -*- 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 .activity_date import activity_date +from .activity_scope import activity_scope +from .activity_status import activity_status +from .background import background +from .budget import budget +from .capital_spend import capital_spend +from .collaboration_type import collaboration_type +from .contact_info import contact_info +from .country_budget_items import country_budget_items +from .conditions import conditions +from .crs_add import crs_add +from .current_situation import current_situation +from .default_aid_type import default_aid_type +from .default_finance_type import default_finance_type +from .default_flow_type import default_flow_type +from .default_tied_status import default_tied_status +from .document_link import document_link +from .fss import fss +from .goals_overview import goals_overview +from .iati_identifier import iati_identifier +from .legacy_data import legacy_data +from .location import location +from .other_identifier import other_identifier +from .participating_org import participating_org +from .planned_disbursement import planned_disbursement +from .policy_marker import policy_marker +from .project_plan import project_plan +from .recipient_country import recipient_country +from .recipient_region import recipient_region +from .related_activity import related_activity +from .reporting_org import reporting_org +from .result import result +from .sector import sector +from .subtitle import subtitle +from .sustainability import sustainability +from .summary import summary +from .target_group import target_group +from .title import title +from .transaction import transaction + +__all__ = [ + 'activity_date', + 'activity_scope', + 'activity_status', + 'background', + 'budget', + 'capital_spend', + 'collaboration_type', + 'conditions', + 'contact_info', + 'country_budget_items', + 'crs_add', + 'current_situation', + 'default_aid_type', + 'default_finance_type', + 'default_flow_type', + 'default_tied_status', + 'document_link', + 'fss', + 'goals_overview', + 'iati_identifier', + 'legacy_data', + 'location', + 'participating_org', + 'planned_disbursement', + 'policy_marker', + 'project_plan', + 'recipient_country', + 'recipient_region', + 'related_activity', + 'reporting_org', + 'result', + 'sector', + 'subtitle', + 'sustainability', + 'summary', + 'target_group', + 'title', + 'transaction', +] diff --git a/akvo/iati/exports/elements/activity_date.py b/akvo/iati/exports/elements/activity_date.py new file mode 100644 index 0000000000..ad3aa082f7 --- /dev/null +++ b/akvo/iati/exports/elements/activity_date.py @@ -0,0 +1,43 @@ +# -*- 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 lxml import etree + + +def activity_date(project): + """ + Generate the activity-date elements. + + :param project: Project object + :return: A list of Etree elements + """ + activity_date_elements = [] + + if project.date_start_planned: + date_start_planned_element = etree.Element("activity-date") + date_start_planned_element.attrib['iso-date'] = str(project.date_start_planned) + date_start_planned_element.attrib['type'] = '1' + activity_date_elements.append(date_start_planned_element) + + if project.date_start_actual: + date_start_actual_element = etree.Element("activity-date") + date_start_actual_element.attrib['iso-date'] = str(project.date_start_actual) + date_start_actual_element.attrib['type'] = '2' + activity_date_elements.append(date_start_actual_element) + + if project.date_end_planned: + date_end_planned_element = etree.Element("activity-date") + date_end_planned_element.attrib['iso-date'] = str(project.date_end_planned) + date_end_planned_element.attrib['type'] = '3' + activity_date_elements.append(date_end_planned_element) + + if project.date_end_actual: + date_end_actual_element = etree.Element("activity-date") + date_end_actual_element.attrib['iso-date'] = str(project.date_end_actual) + date_end_actual_element.attrib['type'] = '4' + activity_date_elements.append(date_end_actual_element) + + return activity_date_elements diff --git a/akvo/iati/exports/elements/activity_scope.py b/akvo/iati/exports/elements/activity_scope.py new file mode 100644 index 0000000000..6f5f7aaab6 --- /dev/null +++ b/akvo/iati/exports/elements/activity_scope.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def activity_scope(project): + """ + Generate the activity-scope element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.project_scope: + element = etree.Element("activity-scope") + element.attrib['code'] = project.project_scope + return [element] + + return [] diff --git a/akvo/iati/exports/elements/activity_status.py b/akvo/iati/exports/elements/activity_status.py new file mode 100644 index 0000000000..f4f51ced84 --- /dev/null +++ b/akvo/iati/exports/elements/activity_status.py @@ -0,0 +1,31 @@ +# -*- 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 lxml import etree + +STATUS_TO_CODE = { + 'N': '6', + 'H': '1', + 'A': '2', + 'C': '3', + 'L': '5', + 'R': '6', +} + + +def activity_status(project): + """ + Generate the activity-status element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.status in STATUS_TO_CODE.keys(): + element = etree.Element("activity-status") + element.attrib['code'] = STATUS_TO_CODE[project.status] + return [element] + + return [] diff --git a/akvo/iati/exports/elements/background.py b/akvo/iati/exports/elements/background.py new file mode 100644 index 0000000000..ff31589402 --- /dev/null +++ b/akvo/iati/exports/elements/background.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def background(project): + """ + Generate the background element, a description element with type "1" and akvo type "6". + + :param project: Project object + :return: A list of Etree elements + """ + if project.background: + element = etree.Element("description") + element.attrib['type'] = '1' + element.attrib['{http://akvo.org/iati-activities}type'] = '6' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.background + return [element] + + return [] diff --git a/akvo/iati/exports/elements/budget.py b/akvo/iati/exports/elements/budget.py new file mode 100644 index 0000000000..304461de5d --- /dev/null +++ b/akvo/iati/exports/elements/budget.py @@ -0,0 +1,48 @@ +# -*- 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 lxml import etree + + +def budget(project): + """ + Generate the budget elements. + + :param project: Project object + :return: A list of Etree elements + """ + budget_elements = [] + + for budget_item in project.budget_items.all(): + if budget_item.amount and budget_item.period_start and budget_item.period_end: + element = etree.Element("budget") + + if budget_item.type: + element.attrib['type'] = budget_item.type + + period_start_element = etree.SubElement(element, "period-start") + period_start_element.attrib['iso-date'] = str(budget_item.period_start) + + period_end_element = etree.SubElement(element, "period-end") + period_end_element.attrib['iso-date'] = str(budget_item.period_end) + + value_element = etree.SubElement(element, "value") + value_element.text = str(budget_item.amount) + + if budget_item.value_date: + value_element.attrib['value-date'] = str(budget_item.value_date) + + if budget_item.currency: + value_element.attrib['currency'] = budget_item.currency + + if budget_item.other_extra: + value_element.attrib['{http://akvo.org/iati-activities}label'] = budget_item.other_extra + elif budget_item.label.label: + value_element.attrib['{http://akvo.org/iati-activities}label'] = budget_item.label.label + + budget_elements.append(element) + + return budget_elements diff --git a/akvo/iati/exports/elements/capital_spend.py b/akvo/iati/exports/elements/capital_spend.py new file mode 100644 index 0000000000..d73e895575 --- /dev/null +++ b/akvo/iati/exports/elements/capital_spend.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def capital_spend(project): + """ + Generate the capital-spend element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.capital_spend_percentage: + element = etree.Element("capital-spend") + element.attrib['percentage'] = str(project.capital_spend_percentage) + return [element] + + return [] diff --git a/akvo/iati/exports/elements/collaboration_type.py b/akvo/iati/exports/elements/collaboration_type.py new file mode 100644 index 0000000000..1dd345c947 --- /dev/null +++ b/akvo/iati/exports/elements/collaboration_type.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def collaboration_type(project): + """ + Generate the collaboration-type element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.collaboration_type: + element = etree.Element("collaboration-type") + element.attrib['code'] = project.collaboration_type + return [element] + + return [] diff --git a/akvo/iati/exports/elements/conditions.py b/akvo/iati/exports/elements/conditions.py new file mode 100644 index 0000000000..c4d31461a2 --- /dev/null +++ b/akvo/iati/exports/elements/conditions.py @@ -0,0 +1,35 @@ +# -*- 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 lxml import etree + + +def conditions(project): + """ + Generate the conditions element. + + :param project: Project object + :return: A list of Etree elements + """ + conditions_element = etree.Element("conditions") + + if project.conditions.all(): + conditions_element.attrib['attached'] = '1' + else: + conditions_element.attrib['attached'] = '0' + + for condition in project.conditions.all(): + if condition.type: + condition_element = etree.SubElement(conditions_element, "condition") + condition_element.attrib['type'] = condition.type + + if condition.text: + narrative_element = etree.SubElement(condition_element, "narrative") + narrative_element.text = condition.text + + conditions_element.append(condition_element) + + return [conditions_element] diff --git a/akvo/iati/exports/elements/contact_info.py b/akvo/iati/exports/elements/contact_info.py new file mode 100644 index 0000000000..54e900299e --- /dev/null +++ b/akvo/iati/exports/elements/contact_info.py @@ -0,0 +1,64 @@ +# -*- 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 lxml import etree + + +def contact_info(project): + """ + Generate the contact-info elements. + + :param project: Project object + :return: A list of Etree elements + """ + contact_info_elements = [] + + for contact in project.contacts.all(): + element = etree.Element("contact-info") + + if contact.type: + element.attrib['type'] = str(contact.type) + + if contact.organisation: + organisation_element = etree.SubElement(element, "organisation") + narrative_element = etree.SubElement(organisation_element, "narrative") + narrative_element.text = contact.organisation + + if contact.department: + department_element = etree.SubElement(element, "department") + narrative_element = etree.SubElement(department_element, "narrative") + narrative_element.text = contact.department + + if contact.person_name: + person_name_element = etree.SubElement(element, "person-name") + narrative_element = etree.SubElement(person_name_element, "narrative") + narrative_element.text = contact.person_name + + if contact.job_title: + job_title_element = etree.SubElement(element, "job-title") + narrative_element = etree.SubElement(job_title_element, "narrative") + narrative_element.text = contact.job_title + + if contact.telephone: + telephone_element = etree.SubElement(element, "telephone") + telephone_element.text = contact.telephone + + if contact.email: + email_element = etree.SubElement(element, "email") + email_element.text = contact.email + + if contact.website: + website_element = etree.SubElement(element, "website") + website_element.text = contact.website + + if contact.mailing_address: + mailing_address_element = etree.SubElement(element, "mailing-address") + narrative_element = etree.SubElement(mailing_address_element, "narrative") + narrative_element.text = contact.mailing_address + + contact_info_elements.append(element) + + return contact_info_elements diff --git a/akvo/iati/exports/elements/country_budget_items.py b/akvo/iati/exports/elements/country_budget_items.py new file mode 100644 index 0000000000..09145bcb19 --- /dev/null +++ b/akvo/iati/exports/elements/country_budget_items.py @@ -0,0 +1,37 @@ +# -*- 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 lxml import etree + + +def country_budget_items(project): + """ + Generate the country-budget-items element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.country_budget_items.all(): + country_budget_items_element = etree.Element("country-budget-items") + else: + return [] + + if project.country_budget_vocabulary: + country_budget_items_element.attrib['vocabulary'] = project.country_budget_vocabulary + + for budget_item in project.country_budget_items.all(): + if budget_item.code: + element = etree.SubElement(country_budget_items_element, "budget-item") + element.attrib['code'] = budget_item.code + + if budget_item.description: + description_element = etree.SubElement(element, "description") + narrative_element = etree.SubElement(description_element, "narrative") + narrative_element.text = budget_item.description + + country_budget_items_element.append(element) + + return [country_budget_items_element] diff --git a/akvo/iati/exports/elements/crs_add.py b/akvo/iati/exports/elements/crs_add.py new file mode 100644 index 0000000000..f676ce1413 --- /dev/null +++ b/akvo/iati/exports/elements/crs_add.py @@ -0,0 +1,91 @@ +# -*- 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 lxml import etree + + +def crs_add(project): + """ + Generate the crs-add element. + + :param project: Project object + :return: A list of Etree elements + """ + try: + crs = project.crsadd + except: + return [] + + element = etree.Element("crs-add") + + for flag in crs.other_flags.all(): + if flag.code and flag.significance is not None: + other_flag_element = etree.SubElement(element, "other-flags") + other_flag_element.attrib['code'] = flag.code + other_flag_element.attrib['significance'] = '1' if flag.significance else '0' + + element.append(other_flag_element) + + loan_terms_element = etree.SubElement(element, "loan-terms") + + if crs.loan_terms_rate1: + loan_terms_element.attrib['rate-1'] = str(crs.loan_terms_rate1) + + if crs.loan_terms_rate2: + loan_terms_element.attrib['rate-2'] = str(crs.loan_terms_rate2) + + if crs.repayment_type: + repayment_type_element = etree.SubElement(loan_terms_element, "repayment-type") + repayment_type_element.attrib['code'] = crs.repayment_type + + if crs.repayment_plan: + repayment_plan_element = etree.SubElement(loan_terms_element, "repayment-plan") + repayment_plan_element.attrib['code'] = crs.repayment_plan + + if crs.commitment_date: + commitment_date_element = etree.SubElement(loan_terms_element, "commitment-date") + commitment_date_element.attrib['iso-date'] = str(crs.commitment_date) + + if crs.repayment_first_date: + repayment_first_date_element = etree.SubElement(loan_terms_element, "repayment-first-date") + repayment_first_date_element.attrib['iso-date'] = str(crs.repayment_first_date) + + if crs.repayment_final_date: + repayment_final_date_element = etree.SubElement(loan_terms_element, "repayment-final-date") + repayment_final_date_element.attrib['iso-date'] = str(crs.repayment_final_date) + + element.append(loan_terms_element) + + loan_status_element = etree.SubElement(element, "loan-status") + + if crs.loan_status_year: + loan_status_element.attrib['year'] = str(crs.loan_status_year) + + if crs.loan_status_currency: + loan_status_element.attrib['currency'] = crs.loan_status_currency + + if crs.loan_status_value_date: + loan_status_element.attrib['value-date'] = str(crs.loan_status_value_date) + + if crs.interest_received: + interest_received_element = etree.SubElement(loan_status_element, "interest-received") + interest_received_element.text = str(crs.interest_received) + + if crs.principal_outstanding: + principal_outstanding_element = etree.SubElement(loan_status_element, "principal-outstanding") + principal_outstanding_element.text = str(crs.principal_outstanding) + + if crs.principal_arrears: + principal_arrears_element = etree.SubElement(loan_status_element, "principal-arrears") + principal_arrears_element.text = str(crs.principal_arrears) + + if crs.interest_arrears: + interest_arrears_element = etree.SubElement(loan_status_element, "interest-arrears") + interest_arrears_element.text = str(crs.interest_arrears) + + element.append(loan_status_element) + + return [element] diff --git a/akvo/iati/exports/elements/current_situation.py b/akvo/iati/exports/elements/current_situation.py new file mode 100644 index 0000000000..9b4f9e8075 --- /dev/null +++ b/akvo/iati/exports/elements/current_situation.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def current_situation(project): + """ + Generate the current situation element, a description element with type "1" and akvo type "9". + + :param project: Project object + :return: A list of Etree elements + """ + if project.current_status: + element = etree.Element("description") + element.attrib['type'] = '1' + element.attrib['{http://akvo.org/iati-activities}type'] = '9' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.current_status + return [element] + + return [] diff --git a/akvo/iati/exports/elements/default_aid_type.py b/akvo/iati/exports/elements/default_aid_type.py new file mode 100644 index 0000000000..08c1e121b5 --- /dev/null +++ b/akvo/iati/exports/elements/default_aid_type.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def default_aid_type(project): + """ + Generate the default-aid-type element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.default_aid_type: + element = etree.Element("default-aid-type") + element.attrib['code'] = project.default_aid_type + return [element] + + return [] diff --git a/akvo/iati/exports/elements/default_finance_type.py b/akvo/iati/exports/elements/default_finance_type.py new file mode 100644 index 0000000000..28a53bcccb --- /dev/null +++ b/akvo/iati/exports/elements/default_finance_type.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def default_finance_type(project): + """ + Generate the default-finance-type element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.default_finance_type: + element = etree.Element("default-finance-type") + element.attrib['code'] = project.default_finance_type + return [element] + + return [] diff --git a/akvo/iati/exports/elements/default_flow_type.py b/akvo/iati/exports/elements/default_flow_type.py new file mode 100644 index 0000000000..40656f3804 --- /dev/null +++ b/akvo/iati/exports/elements/default_flow_type.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def default_flow_type(project): + """ + Generate the default-flow-type element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.default_flow_type: + element = etree.Element("default-flow-type") + element.attrib['code'] = project.default_flow_type + return [element] + + return [] diff --git a/akvo/iati/exports/elements/default_tied_status.py b/akvo/iati/exports/elements/default_tied_status.py new file mode 100644 index 0000000000..434a911932 --- /dev/null +++ b/akvo/iati/exports/elements/default_tied_status.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def default_tied_status(project): + """ + Generate the default-aid-type element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.default_tied_status: + element = etree.Element("default-tied-status") + element.attrib['code'] = project.default_tied_status + return [element] + + return [] diff --git a/akvo/iati/exports/elements/document_link.py b/akvo/iati/exports/elements/document_link.py new file mode 100644 index 0000000000..9b7ea7b8cf --- /dev/null +++ b/akvo/iati/exports/elements/document_link.py @@ -0,0 +1,104 @@ +# -*- 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 lxml import etree + + +def document_link(project): + """ + Generate the document-link elements. + + :param project: Project object + :return: A list of Etree elements + """ + document_link_elements = [] + + if project.current_image: + current_image_element = etree.Element("document-link") + current_image_element.attrib['url'] = "http://rsr.akvo.org" + project.current_image.url + current_image_element.attrib['format'] = "image/jpeg" + + title_element = etree.SubElement(current_image_element, "title") + narrative_element = etree.SubElement(title_element, "narrative") + + if project.current_image_caption or project.current_image_credit: + if project.current_image_caption and project.current_image_credit: + narrative_element.text = "%s, credit: %s" % ( + project.current_image_caption, + project.current_image_credit + ) + elif project.current_image_caption: + narrative_element.text = project.current_image_caption + elif project.current_image_credit: + narrative_element.text = "Credit: %s" % (project.current_image_credit,) + else: + narrative_element.text = "Project photo" + + category_element = etree.SubElement(current_image_element, "category") + category_element.attrib['code'] = "A12" + + document_link_elements.append(current_image_element) + + for link in project.links.all(): + if link.url: + link_element = etree.Element("document-link") + link_element.attrib['url'] = link.url + link_element.attrib['format'] = "application/http" + + title_element = etree.SubElement(link_element, "title") + narrative_element = etree.SubElement(title_element, "narrative") + narrative_element.text = link.caption if link.caption else "Project link" + + category_element = etree.SubElement(link_element, "category") + category_element.attrib['code'] = "A12" + + document_link_elements.append(link_element) + + for document in project.documents.all(): + if document.url or document.document: + document_element = etree.Element("document-link") + + if document.url: + document_element.attrib['url'] = document.url + elif document.document: + document_element.attrib['url'] = "http://rsr.akvo.org" + document.document.url + + if document.format: + document_element.attrib['format'] = document.format + + title_element = etree.SubElement(document_element, "title") + narrative_element = etree.SubElement(title_element, "narrative") + narrative_element.text = document.title if document.title else "Project document" + + if document.category: + category_element = etree.SubElement(document_element, "category") + category_element.attrib['code'] = document.category + + if document.language: + language_element = etree.SubElement(document_element, "language") + language_element.attrib['code'] = document.language + + document_link_elements.append(document_element) + + for update in project.project_updates.all(): + update_element = etree.Element("document-link") + update_element.attrib['url'] = "http://rsr.akvo.org/project/%s/update/%s/" % (str(project.pk), str(update.pk)) + update_element.attrib['format'] = "application/http" + + title_element = etree.SubElement(update_element, "title") + narrative_element = etree.SubElement(title_element, "narrative") + narrative_element.text = update.title if update.title else "Project update" + + category_element = etree.SubElement(update_element, "category") + category_element.attrib['code'] = "A12" + + if update.language: + language_element = etree.SubElement(update_element, "language") + language_element.attrib['code'] = update.language + + document_link_elements.append(update_element) + + return document_link_elements diff --git a/akvo/iati/exports/elements/fss.py b/akvo/iati/exports/elements/fss.py new file mode 100644 index 0000000000..4645e5cb71 --- /dev/null +++ b/akvo/iati/exports/elements/fss.py @@ -0,0 +1,49 @@ +# -*- 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 lxml import etree + + +def fss(project): + """ + Generate the fss element. + + :param project: Project object + :return: A list of Etree elements + """ + try: + fss_object = project.fss + except: + return [] + + element = etree.Element("fss") + + if fss_object.extraction_date: + element.attrib['extraction-date'] = str(fss_object.extraction_date) + + if fss_object.priority is not None: + element.attrib['priority'] = '1' if fss_object.priority else '0' + + if fss_object.phaseout_year: + element.attrib['phaseout-year'] = str(fss_object.phaseout_year) + + for forecast in fss_object.forecasts.all(): + if forecast.value: + forecast_element = etree.SubElement(element, "forecast") + forecast_element.text = str(forecast.value) + + if forecast.year: + forecast_element.attrib['year'] = str(forecast.year) + + if forecast.value_date: + forecast_element.attrib['value-date'] = str(forecast.value_date) + + if forecast.currency: + forecast_element.attrib['currency'] = str(forecast.currency) + + element.append(forecast_element) + + return [element] diff --git a/akvo/iati/exports/elements/goals_overview.py b/akvo/iati/exports/elements/goals_overview.py new file mode 100644 index 0000000000..af53ddeb55 --- /dev/null +++ b/akvo/iati/exports/elements/goals_overview.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def goals_overview(project): + """ + Generate the goals overview element, a description element with type "2" and akvo type "8". + + :param project: Project object + :return: A list of Etree elements + """ + if project.goals_overview: + element = etree.Element("description") + element.attrib['type'] = '2' + element.attrib['{http://akvo.org/iati-activities}type'] = '8' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.goals_overview + return [element] + + return [] diff --git a/akvo/iati/exports/elements/iati_identifier.py b/akvo/iati/exports/elements/iati_identifier.py new file mode 100644 index 0000000000..9666620b89 --- /dev/null +++ b/akvo/iati/exports/elements/iati_identifier.py @@ -0,0 +1,22 @@ +# -*- 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 lxml import etree + + +def iati_identifier(project): + """ + Generate the iati-identifier element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.iati_activity_id: + element = etree.Element("iati-identifier") + element.text = project.iati_activity_id + return [element] + + return [] diff --git a/akvo/iati/exports/elements/legacy_data.py b/akvo/iati/exports/elements/legacy_data.py new file mode 100644 index 0000000000..0e69acc6e6 --- /dev/null +++ b/akvo/iati/exports/elements/legacy_data.py @@ -0,0 +1,30 @@ +# -*- 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 lxml import etree + + +def legacy_data(project): + """ + Generate the legacy-data element. + + :param project: Project object + :return: A list of Etree elements + """ + legacy_data_elements = [] + + for legacy in project.legacy_data.all(): + if legacy.name and legacy.value: + element = etree.Element("legacy-data") + element.attrib['name'] = legacy.name + element.attrib['value'] = legacy.value + + if legacy.iati_equivalent: + element.attrib['iati-equivalent'] = legacy.iati_equivalent + + legacy_data_elements.append(element) + + return legacy_data_elements diff --git a/akvo/iati/exports/elements/location.py b/akvo/iati/exports/elements/location.py new file mode 100644 index 0000000000..c7518791d6 --- /dev/null +++ b/akvo/iati/exports/elements/location.py @@ -0,0 +1,78 @@ +# -*- 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 lxml import etree + + +def location(project): + """ + Generate the location elements. + + :param project: Project object + :return: A list of Etree elements + """ + location_elements = [] + + for loc in project.locations.all(): + element = etree.Element("location") + + if loc.reference: + element.attrib['ref'] = loc.reference + + if loc.location_reach: + reach_element = etree.SubElement(element, "location-reach") + reach_element.attrib['code'] = loc.location_reach + + if loc.location_code and loc.vocabulary: + id_element = etree.SubElement(element, "location-id") + id_element.attrib['vocabulary'] = loc.vocabulary + id_element.attrib['code'] = loc.location_code + + if loc.name: + name_element = etree.SubElement(element, "name") + narrative_element = etree.SubElement(name_element, "narrative") + narrative_element.text = loc.name + + if loc.description: + description_element = etree.SubElement(element, "description") + narrative_element = etree.SubElement(description_element, "narrative") + narrative_element.text = loc.description + + if loc.activity_description: + activity_description_element = etree.SubElement(element, "activity-description") + narrative_element = etree.SubElement(activity_description_element, "narrative") + narrative_element.text = loc.activity_description + + for administrative in loc.administratives.all(): + if administrative.code and administrative.vocabulary: + administrative_element = etree.SubElement(element, "administrative") + administrative_element.attrib['vocabulary'] = administrative.vocabulary + administrative_element.attrib['code'] = administrative.code + + if administrative.level: + administrative_element.attrib['level'] = str(administrative.level) + + if loc.latitude and loc.longitude: + point_element = etree.SubElement(element, "point") + point_element.attrib['srsName'] = 'http://www.opengis.net/def/crs/EPSG/0/4326' + pos_element = etree.SubElement(point_element, "pos") + pos_element.text = "%s %s" % (str(loc.latitude), str(loc.longitude)) + + if loc.exactness: + exactness_element = etree.SubElement(element, "exactness") + exactness_element.attrib['code'] = str(loc.exactness) + + if loc.location_class: + class_element = etree.SubElement(element, "location-class") + class_element.attrib['code'] = str(loc.location_class) + + if loc.feature_designation: + feature_element = etree.SubElement(element, "feature-designation") + feature_element.attrib['code'] = str(loc.feature_designation) + + location_elements.append(element) + + return location_elements diff --git a/akvo/iati/exports/elements/other_identifier.py b/akvo/iati/exports/elements/other_identifier.py new file mode 100644 index 0000000000..bbad59c9a1 --- /dev/null +++ b/akvo/iati/exports/elements/other_identifier.py @@ -0,0 +1,53 @@ +# -*- 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 lxml import etree + + +def other_identifier(project): + """ + Generate the other-identifier elements. + + :param project: Project object + :return: A list of Etree elements + """ + other_identifier_elements = [] + + element = etree.Element("other-identifier") + element.attrib['ref'] = str(project.pk) + element.attrib['type'] = 'B9' + + owner_org_element = etree.SubElement(element, "owner-org") + owner_org_element.attrib['ref'] = 'NL-KVK-27327087' + + narrative_element = etree.SubElement(owner_org_element, "narrative") + narrative_element.text = 'Akvo Foundation' + + other_identifier_elements.append(element) + + for partnership in project.partnerships.all(): + org = partnership.organisation + + if partnership.internal_id: + element = etree.Element("other-identifier") + element.attrib['ref'] = str(partnership.internal_id) + element.attrib['type'] = 'A1' if org == project.sync_owner else 'B9' + + owner_org_element = etree.SubElement(element, "owner-org") + + if org.iati_org_id: + owner_org_element.attrib['ref'] = org.iati_org_id + + narrative_element = etree.SubElement(owner_org_element, "narrative") + + if org.long_name: + narrative_element.text = org.long_name + elif org.name: + narrative_element.text = org.name + + other_identifier_elements.append(element) + + return other_identifier_elements diff --git a/akvo/iati/exports/elements/participating_org.py b/akvo/iati/exports/elements/participating_org.py new file mode 100644 index 0000000000..a8346acdb7 --- /dev/null +++ b/akvo/iati/exports/elements/participating_org.py @@ -0,0 +1,50 @@ +# -*- 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 lxml import etree + +TYPE_TO_CODE = { + 'funding': '1', + 'support': '2', + 'sponsor': '3', + 'field': '4', +} + + +def participating_org(project): + """ + Generate the participating-org element. + + :param project: Project object + :return: A list of Etree elements + """ + partnership_elements = [] + + from akvo.rsr.models import Partnership + + for partnership in project.partnerships.all(): + org = partnership.organisation + element = etree.Element("participating-org") + + if org.iati_org_id: + element.attrib['ref'] = org.iati_org_id + + if org.new_organisation_type: + element.attrib['type'] = str(org.new_organisation_type) + # don't include old akvo sponsor partner value when checking + if partnership.iati_organisation_role in Partnership.IATI_ROLE_LIST[:-1]: + element.attrib['role'] = str(partnership.iati_organisation_role) + + narrative_element = etree.SubElement(element, "narrative") + + if org.long_name: + narrative_element.text = org.long_name + elif org.name: + narrative_element.text = org.name + + partnership_elements.append(element) + + return partnership_elements diff --git a/akvo/iati/exports/elements/planned_disbursement.py b/akvo/iati/exports/elements/planned_disbursement.py new file mode 100644 index 0000000000..5955556eb5 --- /dev/null +++ b/akvo/iati/exports/elements/planned_disbursement.py @@ -0,0 +1,45 @@ +# -*- 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 lxml import etree + + +def planned_disbursement(project): + """ + Generate the planned-disbursement elements. + + :param project: Project object + :return: A list of Etree elements + """ + planned_disbursement_elements = [] + + for planned_disbursement in project.planned_disbursements.all(): + if planned_disbursement.value: + element = etree.Element("planned-disbursement") + + if planned_disbursement.type: + element.attrib['type'] = planned_disbursement.type + + if planned_disbursement.period_start: + period_start_element = etree.SubElement(element, "period-start") + period_start_element.attrib['iso-date'] = str(planned_disbursement.period_start) + + if planned_disbursement.period_end: + period_end_element = etree.SubElement(element, "period-end") + period_end_element.attrib['iso-date'] = str(planned_disbursement.period_end) + + value_element = etree.SubElement(element, "value") + value_element.text = str(planned_disbursement.value) + + if planned_disbursement.value_date: + value_element.attrib['value-date'] = str(planned_disbursement.value_date) + + if planned_disbursement.currency: + value_element.attrib['currency'] = planned_disbursement.currency + + planned_disbursement_elements.append(element) + + return planned_disbursement_elements diff --git a/akvo/iati/exports/elements/policy_marker.py b/akvo/iati/exports/elements/policy_marker.py new file mode 100644 index 0000000000..faf553cc80 --- /dev/null +++ b/akvo/iati/exports/elements/policy_marker.py @@ -0,0 +1,34 @@ +# -*- 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 lxml import etree + + +def policy_marker(project): + """ + Generate the policy-marker element. + + :param project: Project object + :return: A list of Etree elements + """ + policy_marker_elements = [] + + for policy in project.policy_markers.all(): + if policy.policy_marker and policy.significance: + element = etree.Element("policy-marker") + element.attrib['code'] = policy.policy_marker + element.attrib['significance'] = policy.significance + + if policy.vocabulary: + element.attrib['vocabulary'] = policy.vocabulary + + if policy.description: + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = policy.description + + policy_marker_elements.append(element) + + return policy_marker_elements diff --git a/akvo/iati/exports/elements/project_plan.py b/akvo/iati/exports/elements/project_plan.py new file mode 100644 index 0000000000..afce1a0aba --- /dev/null +++ b/akvo/iati/exports/elements/project_plan.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def project_plan(project): + """ + Generate the project plan element, a description element with type "1" and akvo type "7". + + :param project: Project object + :return: A list of Etree elements + """ + if project.project_plan: + element = etree.Element("description") + element.attrib['type'] = '1' + element.attrib['{http://akvo.org/iati-activities}type'] = '7' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.project_plan + return [element] + + return [] diff --git a/akvo/iati/exports/elements/recipient_country.py b/akvo/iati/exports/elements/recipient_country.py new file mode 100644 index 0000000000..b9baa9671a --- /dev/null +++ b/akvo/iati/exports/elements/recipient_country.py @@ -0,0 +1,33 @@ +# -*- 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 lxml import etree + + +def recipient_country(project): + """ + Generate the recipient-country element. + + :param project: Project object + :return: A list of Etree elements + """ + recipient_country_elements = [] + + for country in project.recipient_countries.all(): + if country.country: + element = etree.Element("recipient-country") + element.attrib['code'] = country.country + + if country.percentage: + element.attrib['percentage'] = str(country.percentage) + + if country.text: + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = country.text + + recipient_country_elements.append(element) + + return recipient_country_elements diff --git a/akvo/iati/exports/elements/recipient_region.py b/akvo/iati/exports/elements/recipient_region.py new file mode 100644 index 0000000000..bda1134d13 --- /dev/null +++ b/akvo/iati/exports/elements/recipient_region.py @@ -0,0 +1,36 @@ +# -*- 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 lxml import etree + + +def recipient_region(project): + """ + Generate the recipient-region element. + + :param project: Project object + :return: A list of Etree elements + """ + recipient_region_elements = [] + + for region in project.recipient_regions.all(): + if region.region: + element = etree.Element("recipient-region") + element.attrib['code'] = region.region + + if region.percentage: + element.attrib['percentage'] = str(region.percentage) + + if region.region_vocabulary: + element.attrib['vocabulary'] = str(region.region_vocabulary) + + if region.text: + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = region.text + + recipient_region_elements.append(element) + + return recipient_region_elements diff --git a/akvo/iati/exports/elements/related_activity.py b/akvo/iati/exports/elements/related_activity.py new file mode 100644 index 0000000000..bea90a3e68 --- /dev/null +++ b/akvo/iati/exports/elements/related_activity.py @@ -0,0 +1,43 @@ +# -*- 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 lxml import etree + + +def related_activity(project): + """ + Generate the related-activity elements. + + :param project: Project object + :return: A list of Etree elements + """ + related_activity_elements = [] + + for related_project in project.related_projects.all(): + if related_project.related_project and related_project.relation: + if related_project.related_project.iati_activity_id: + element = etree.Element("related-activity") + element.attrib['ref'] = related_project.related_project.iati_activity_id + element.attrib['type'] = related_project.relation + + related_activity_elements.append(element) + + elif related_project.related_iati_id and related_project.relation: + element = etree.Element("related-activity") + element.attrib['ref'] = related_project.related_iati_id + element.attrib['type'] = related_project.relation + + related_activity_elements.append(element) + + for related_to_project in project.related_to_projects.all(): + if related_to_project.project.iati_activity_id and related_to_project.relation: + element = etree.Element("related-activity") + element.attrib['ref'] = related_to_project.project.iati_activity_id + element.attrib['type'] = related_to_project.relation + + related_activity_elements.append(element) + + return related_activity_elements diff --git a/akvo/iati/exports/elements/reporting_org.py b/akvo/iati/exports/elements/reporting_org.py new file mode 100644 index 0000000000..be874b9f42 --- /dev/null +++ b/akvo/iati/exports/elements/reporting_org.py @@ -0,0 +1,39 @@ +# -*- 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 lxml import etree + + +def reporting_org(project): + """ + Generate the reporting-org element. + + :param project: Project object + :return: A list of Etree elements + """ + org = project.sync_owner + if org: + element = etree.Element("reporting-org") + + if org.iati_org_id: + element.attrib['ref'] = org.iati_org_id + + if project.sync_owner_secondary_reporter is not None: + element.attrib['secondary-reporter'] = '1' if project.sync_owner_secondary_reporter else '0' + + if org.new_organisation_type: + element.attrib['type'] = str(org.new_organisation_type) + + narrative_element = etree.SubElement(element, "narrative") + + if org.long_name: + narrative_element.text = org.long_name + elif org.name: + narrative_element.text = org.name + + return [element] + + return [] diff --git a/akvo/iati/exports/elements/result.py b/akvo/iati/exports/elements/result.py new file mode 100644 index 0000000000..10ba4d3e17 --- /dev/null +++ b/akvo/iati/exports/elements/result.py @@ -0,0 +1,102 @@ +# -*- 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 lxml import etree + + +def result(project): + """ + Generate the result elements. + + :param project: Project object + :return: A list of Etree elements + """ + result_elements = [] + + for res in project.results.all(): + element = etree.Element("result") + + if res.type: + element.attrib['type'] = res.type + + if res.aggregation_status is not None: + element.attrib['aggregation-status'] = '1' if res.aggregation_status else '0' + + if res.title: + title_element = etree.SubElement(element, "title") + narrative_element = etree.SubElement(title_element, "narrative") + narrative_element.text = res.title + + if res.description: + description_element = etree.SubElement(element, "description") + narrative_element = etree.SubElement(description_element, "narrative") + narrative_element.text = res.description + + for indicator in res.indicators.all(): + indicator_element = etree.SubElement(element, "indicator") + + if indicator.measure: + indicator_element.attrib['measure'] = indicator.measure + + if indicator.ascending is not None: + indicator_element.attrib['ascending'] = '1' if indicator.ascending else '0' + + if indicator.title: + title_element = etree.SubElement(indicator_element, "title") + narrative_element = etree.SubElement(title_element, "narrative") + narrative_element.text = indicator.title + + if indicator.description: + description_element = etree.SubElement(indicator_element, "description") + narrative_element = etree.SubElement(description_element, "narrative") + narrative_element.text = res.description + + if indicator.baseline_year and indicator.baseline_value: + baseline_element = etree.SubElement(indicator_element, "baseline") + baseline_element.attrib['year'] = str(indicator.baseline_year) + baseline_element.attrib['value'] = indicator.baseline_value + + if indicator.baseline_comment: + comment_element = etree.SubElement(baseline_element, "comment") + narrative_element = etree.SubElement(comment_element, "narrative") + narrative_element.text = indicator.baseline_comment + + for period in indicator.periods.all(): + period_element = etree.SubElement(indicator_element, "period") + + if period.period_start: + period_start_element = etree.SubElement(period_element, "period-start") + period_start_element.attrib['iso-date'] = str(period.period_start) + + if period.period_end: + period_end_element = etree.SubElement(period_element, "period-end") + period_end_element.attrib['iso-date'] = str(period.period_end) + + if period.target_value: + target_element = etree.SubElement(period_element, "target") + target_element.attrib['value'] = period.target_value + + if period.target_comment: + comment_element = etree.SubElement(target_element, "comment") + narrative_element = etree.SubElement(comment_element, "narrative") + narrative_element.text = period.target_comment + + if period.actual_value: + actual_element = etree.SubElement(period_element, "actual") + actual_element.attrib['value'] = period.actual_value + + if period.actual_comment: + comment_element = etree.SubElement(actual_element, "comment") + narrative_element = etree.SubElement(comment_element, "narrative") + narrative_element.text = period.actual_comment + + indicator_element.append(period_element) + + element.append(indicator_element) + + result_elements.append(element) + + return result_elements diff --git a/akvo/iati/exports/elements/sector.py b/akvo/iati/exports/elements/sector.py new file mode 100644 index 0000000000..a05bd2f16f --- /dev/null +++ b/akvo/iati/exports/elements/sector.py @@ -0,0 +1,36 @@ +# -*- 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 lxml import etree + + +def sector(project): + """ + Generate the sector elements. + + :param project: Project object + :return: A list of Etree elements + """ + sector_elements = [] + + for sec in project.sectors.all(): + if sec.sector_code: + element = etree.Element("sector") + element.attrib['code'] = sec.sector_code + + if not sec.vocabulary or sec.vocabulary == 'DAC': + element.attrib['vocabulary'] = '1' + elif sec.vocabulary == 'DAC-3': + element.attrib['vocabulary'] = '2' + else: + element.attrib['vocabulary'] = sec.vocabulary + + if sec.percentage: + element.attrib['percentage'] = str(sec.percentage) + + sector_elements.append(element) + + return sector_elements diff --git a/akvo/iati/exports/elements/subtitle.py b/akvo/iati/exports/elements/subtitle.py new file mode 100644 index 0000000000..de05017c90 --- /dev/null +++ b/akvo/iati/exports/elements/subtitle.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def subtitle(project): + """ + Generate the subtitle element, a description element with type "1" and akvo type "4". + + :param project: Project object + :return: A list of Etree elements + """ + if project.subtitle: + element = etree.Element("description") + element.attrib['type'] = '1' + element.attrib['{http://akvo.org/iati-activities}type'] = '4' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.subtitle + return [element] + + return [] diff --git a/akvo/iati/exports/elements/summary.py b/akvo/iati/exports/elements/summary.py new file mode 100644 index 0000000000..bd894d8c6f --- /dev/null +++ b/akvo/iati/exports/elements/summary.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def summary(project): + """ + Generate the summary element, a description element with type "1" and akvo type "5". + + :param project: Project object + :return: A list of Etree elements + """ + if project.project_plan_summary: + element = etree.Element("description") + element.attrib['type'] = '1' + element.attrib['{http://akvo.org/iati-activities}type'] = '5' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.project_plan_summary + return [element] + + return [] diff --git a/akvo/iati/exports/elements/sustainability.py b/akvo/iati/exports/elements/sustainability.py new file mode 100644 index 0000000000..c19caaa3c9 --- /dev/null +++ b/akvo/iati/exports/elements/sustainability.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def sustainability(project): + """ + Generate the sustainability element, a description element with type "1" and akvo type "10". + + :param project: Project object + :return: A list of Etree elements + """ + if project.sustainability: + element = etree.Element("description") + element.attrib['type'] = '1' + element.attrib['{http://akvo.org/iati-activities}type'] = '10' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.sustainability + return [element] + + return [] diff --git a/akvo/iati/exports/elements/target_group.py b/akvo/iati/exports/elements/target_group.py new file mode 100644 index 0000000000..9f7438a90a --- /dev/null +++ b/akvo/iati/exports/elements/target_group.py @@ -0,0 +1,26 @@ +# -*- 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 lxml import etree + + +def target_group(project): + """ + Generate the target group element, a description element with type "3" and akvo type "3". + + :param project: Project object + :return: A list of Etree elements + """ + if project.target_group: + element = etree.Element("description") + element.attrib['type'] = '3' + element.attrib['{http://akvo.org/iati-activities}type'] = '3' + + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.target_group + return [element] + + return [] diff --git a/akvo/iati/exports/elements/title.py b/akvo/iati/exports/elements/title.py new file mode 100644 index 0000000000..18b90ed5e0 --- /dev/null +++ b/akvo/iati/exports/elements/title.py @@ -0,0 +1,23 @@ +# -*- 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 lxml import etree + + +def title(project): + """ + Generate the title element. + + :param project: Project object + :return: A list of Etree elements + """ + if project.title: + element = etree.Element("title") + narrative_element = etree.SubElement(element, "narrative") + narrative_element.text = project.title + return [element] + + return [] diff --git a/akvo/iati/exports/elements/transaction.py b/akvo/iati/exports/elements/transaction.py new file mode 100644 index 0000000000..b935d07587 --- /dev/null +++ b/akvo/iati/exports/elements/transaction.py @@ -0,0 +1,161 @@ +# -*- 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 lxml import etree + + +def _provider_organisation(element, trans): + """ + Helper function for transaction() + """ + org = trans.provider_organisation + provider_org_element = etree.SubElement(element, "provider-org") + + if trans.provider_organisation_activity: + provider_org_element.attrib['provider-activity-id'] = trans.provider_organisation_activity + + if org.iati_org_id: + provider_org_element.attrib['ref'] = org.iati_org_id + + if org.long_name: + narrative_element = etree.SubElement(provider_org_element, "narrative") + narrative_element.text = org.long_name + elif org.name: + narrative_element = etree.SubElement(provider_org_element, "narrative") + narrative_element.text = org.name + + return element + + +def _receiver_organisation(element, trans): + """ + Helper function for transaction() + """ + org = trans.receiver_organisation + receiver_org_element = etree.SubElement(element, "receiver-org") + + if trans.receiver_organisation_activity: + receiver_org_element.attrib['receiver-activity-id'] = trans.receiver_organisation_activity + + if org.iati_org_id: + receiver_org_element.attrib['ref'] = org.iati_org_id + + if org.long_name: + narrative_element = etree.SubElement(receiver_org_element, "narrative") + narrative_element.text = org.long_name + elif org.name: + narrative_element = etree.SubElement(receiver_org_element, "narrative") + narrative_element.text = org.name + + return element + + +def _sector(element, sector): + """ + Helper function for transaction() + """ + if sector.code: + sector_element = etree.SubElement(element, "sector") + sector_element.attrib['code'] = sector.code + + if not sector.vocabulary or sector.vocabulary == 'DAC': + sector_element.attrib['vocabulary'] = '1' + elif sector.vocabulary == 'DAC-3': + sector_element.attrib['vocabulary'] = '2' + else: + sector_element.attrib['vocabulary'] = sector.vocabulary + + if sector.percentage: + sector_element.attrib['percentage'] = str(sector.percentage) + + if sector.text: + sector_element.text = sector.text + + return element + + +def transaction(project): + """ + Generate the transaction elements. + + :param project: Project object + :return: A list of Etree elements + """ + + transaction_elements = [] + + for trans in project.transactions.all(): + element = etree.Element("transaction") + + if trans.reference: + element.attrib['ref'] = trans.reference + + if trans.transaction_type: + type_element = etree.SubElement(element, "transaction-type") + type_element.attrib['code'] = trans.transaction_type + + if trans.transaction_date: + date_element = etree.SubElement(element, "transaction-date") + date_element.attrib['iso-date'] = str(trans.transaction_date) + + if trans.value: + value_element = etree.SubElement(element, "value") + value_element.text = str(trans.value) + + if trans.currency: + value_element.attrib['currency'] = trans.currency + + if trans.value_date: + value_element.attrib['value-date'] = str(trans.value_date) + + if trans.description: + description_element = etree.SubElement(element, "description") + narrative_element = etree.SubElement(description_element, "narrative") + narrative_element.text = trans.description + + if trans.provider_organisation: + element = _provider_organisation(element, trans) + + if trans.receiver_organisation: + element = _receiver_organisation(element, trans) + + if trans.disbursement_channel: + disbursement_channel_element = etree.SubElement(element, "disbursement-channel") + disbursement_channel_element.attrib['code'] = trans.disbursement_channel + + for sector in trans.sectors.all(): + element = _sector(element, sector) + + if trans.recipient_country: + recipient_country_element = etree.SubElement(element, "recipient-country") + recipient_country_element.attrib['code'] = trans.recipient_country + + if trans.recipient_region: + recipient_region_element = etree.SubElement(element, "recipient-region") + recipient_region_element.attrib['code'] = trans.recipient_region + + if trans.recipient_region_vocabulary: + recipient_region_element.attrib['vocabulary'] = trans.recipient_region_vocabulary + + if trans.flow_type: + flow_type_element = etree.SubElement(element, "flow-type") + flow_type_element.attrib['code'] = trans.flow_type + + if trans.finance_type: + finance_type_element = etree.SubElement(element, "finance-type") + finance_type_element.attrib['code'] = trans.finance_type + + if trans.aid_type: + aid_type_element = etree.SubElement(element, "aid-type") + aid_type_element.attrib['code'] = trans.aid_type + + if trans.tied_status: + tied_status_element = etree.SubElement(element, "tied-status") + tied_status_element.attrib['code'] = trans.tied_status + + transaction_elements.append(element) + + return transaction_elements diff --git a/akvo/iati/imports/iati_import.py b/akvo/iati/imports/iati_import.py index 212f46edc6..4988379eae 100644 --- a/akvo/iati/imports/iati_import.py +++ b/akvo/iati/imports/iati_import.py @@ -5,6 +5,8 @@ # For additional details on the GNU license please see < http://www.gnu.org/licenses/agpl.html >. from ...rsr.models.iati_import_log import IatiImportLog +from ...rsr.exceptions import ProjectException +from .iati_import_activity import IatiImportActivity from django.core.files import File from django.core.files.temp import NamedTemporaryFile @@ -35,7 +37,7 @@ def set_status(self, status): """ Set the status of the IATI import. - :param status: Integer based on the IATI import status codes + :param status: Integer; based on the IATI import status codes """ self.iati_import.status = status self.iati_import.save() @@ -44,7 +46,7 @@ def get_activities(self): """ Get the activities from iati_import.local_file. - :return: An ElementTree node; the root node of the XML + :return: ElementTree; the root node of the XML """ if self.file: parsed_xml = ElementTree.parse(self.file) @@ -108,7 +110,7 @@ def __init__(self, iati_import): """ Initialise the IATI Import process. - :param iati_import: An IatiImport Django ORM object + :param iati_import: IatiImport instance """ self.iati_import = iati_import self.organisation = iati_import.reporting_organisation @@ -125,7 +127,23 @@ def __init__(self, iati_import): # Start import process self.set_status(3) self.activities = self.get_activities() - self.globals = self.activities.items() + for activity in self.activities.findall('iati-activity'): + try: + IatiImportActivity(self.iati_import, activity, self.organisation, self.user, + self.activities.attrib) + except ProjectException as pe: + IatiImportLog.objects.create( + iati_import=self.iati_import, + text=pe.args[0]['message'], + project=pe.args[0]['project'], + error=True + ) + except Exception as e: + IatiImportLog.objects.create( + iati_import=self.iati_import, + text=e, + error=True + ) # Import process complete self.set_status(4) diff --git a/akvo/iati/imports/iati_import_activity.py b/akvo/iati/imports/iati_import_activity.py new file mode 100644 index 0000000000..fb37ac121c --- /dev/null +++ b/akvo/iati/imports/iati_import_activity.py @@ -0,0 +1,94 @@ +# -*- 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 ...rsr.exceptions import ProjectException + +from django.db.models import get_model + +import datetime + + +class IatiImportActivity(object): + def set_start_date(self): + """ + Set the start date of the project import. + """ + self.project_import_log.start_date = datetime.datetime.now() + self.project_import_log.save() + + def set_end_date(self): + """ + Set the end date of the project import. + """ + self.project_import_log.end_date = datetime.datetime.now() + self.project_import_log.save() + + def set_status(self, status): + """ + Set the status of the import + + :param status: Integer; based on the IATI project import status + """ + self.project_import_log.status = status + self.project_import_log.save() + + def set_sync_owner(self): + """ + Check if the project can be edited by the current reporting organisation and set + the sync_owner. + """ + sync_owner = self.project.sync_owner + if not self.created and sync_owner and sync_owner != self.organisation: + self.set_status(4) + raise ProjectException({ + 'message': u'Project has a different sync_owner: %s' % sync_owner.name, + 'project': self.project + }) + self.project.sync_owner = self.organisation + self.project.save() + + def get_or_create_project(self): + """ + Get an existing project or create a new project if no existing project can be found + in the RSR database, based on the IATI identifier. + + :return: Tuple; (Project instance, Boolean indicating whether the project was created) + """ + iati_identifier = self.activity.find('iati-identifier').text + return get_model('rsr', 'project').objects.get_or_create(iati_activity_id=iati_identifier) + + def __init__(self, iati_import, activity, reporting_organisation, user, activities_globals): + """ + Initialize the IATI activity process. + + :param iati_import: IatiImport instance + :param activity: ElementTree; the root node of the IATI activity + :param reporting_organisation: Organisation instance + :param user: User instance + :param activities_globals: Dictionary; contains all global variables + """ + self.iati_import = iati_import + self.activity = activity + self.organisation = reporting_organisation + self.user = user + self.globals = activities_globals + + # Get or create project + self.project, self.created = self.get_or_create_project() + self.project_import_log = get_model('rsr', 'iatiprojectimport').objects.create( + iati_import=self.iati_import, + project=self.project, + action=1 if self.created else 2 + ) + + # Start import process + self.set_status(2) + self.set_start_date() + self.set_sync_owner() + + # Import process finished + self.set_status(3) + self.set_end_date() diff --git a/akvo/rsr/exceptions.py b/akvo/rsr/exceptions.py new file mode 100644 index 0000000000..ed8ca067ba --- /dev/null +++ b/akvo/rsr/exceptions.py @@ -0,0 +1,13 @@ +# -*- 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 >. + + +class ProjectException(Exception): + """ + A specific Exception used in IATI imports for errors belonging to a project. + Assumes that a project is passed together with the message in a dictionary. + """ + pass