예제 #1
0
def make_transaction(transaction, exchange_rates, transaction_types, activities_covid_transactions):
    """
    Main function to build a transaction object
    from the transaction XML.
    """
    provider = get_org(transaction, provider=True)
    receiver = get_org(transaction, provider=False)
    return {
        'iati_identifier': transaction.getparent().find("iati-identifier").text,
        'reporting_org_text': check_encoding(get_narrative(transaction.getparent().find("reporting-org"))),
        'reporting_org_ref': transaction.getparent().find("reporting-org").get("ref"),
        'reporting_org_type': transaction.getparent().find("reporting-org").get("type"),
        'value_USD': get_value_usd(transaction, exchange_rates, transaction.getparent().get('default-currency')),
        'transaction_date': transaction.find('transaction-date').get("iso-date"),
        'transaction_type_code': transaction.find('transaction-type').get("code"),
        'transaction_type': transaction_types[transaction.find('transaction-type').get("code")],
        'provider_text': provider.get('text'),
        'provider_ref': provider.get('ref'),
        'provider_type': provider.get('type'),
        'receiver_text': receiver.get('text'),
        'receiver_ref': receiver.get('ref'),
        'receiver_type': receiver.get('type'),
        'finance_type': get_finance_type(transaction),
        'sectors': get_sectors(transaction),
        'countries_regions': get_countries_regions(transaction),
        'covid_relevant': check_covid_relevant(transaction, activities_covid_transactions),
        'humanitarian': transaction.get('humanitarian') or transaction.getparent().get('humanitarian') or None,
        'covid_matches': get_covid_matches(transaction)
    }
예제 #2
0
def get_organisations(reporting_orgs):
    """
    Take the list of reporting orgs and create a lookup
    dict that can then be used in cases where the
    provider-org or receiver-org only states the ref.
    """
    for org in reporting_orgs:
        if org.get("ref") not in ORGANISATIONS:
            ORGANISATIONS[org.get("ref")] = check_encoding(get_narrative(org))
    return ORGANISATIONS
예제 #3
0
def get_participating_organisations(participating_orgs):
    """
    Returns a dictionary of participating orgs, with
    each organisation role as the key, and the values
    for that particular organisation role
    being a list of organisations with that role.
    """
    orgs = {"1": [], "2": [], "3": [], "4": []}
    for org in participating_orgs:
        orgs[org.get('role')].append({
            'text': get_narrative(org),
            'ref': org.get('ref')
        })
    return orgs
예제 #4
0
def get_org(transaction, provider=True):
    """
    Get organisation data from an organisation object
    (`participating-org`, `provider-org` or `receiver-org`).
    """
    transaction_type = transaction.find("transaction-type").get("code")
    provider_receiver = {True: 'provider', False: 'receiver'}[provider]
    if transaction.find('{}-org'.format(provider_receiver)) is not None:
        _text = get_org_name(
            ref=transaction.find('{}-org'.format(provider_receiver)).get("ref"),
            text=get_narrative(transaction.find('{}-org'.format(provider_receiver)))
        )
        _ref = transaction.find('{}-org'.format(provider_receiver)).get("ref")
        _type = transaction.find('{}-org'.format(provider_receiver)).get("type")
        if (_ref is not None) or (_text is not None):
            return {
                'text': _text or _ref,
                'ref': _ref or _text,
                'type': _type
            }

    role = {
        True: TRANSACTION_TYPES_RULES[transaction_type]['provider'],
        False: TRANSACTION_TYPES_RULES[transaction_type]['receiver']}[provider]
    if ((role == "reporter")
        or (provider==True and transaction_type in ['3', '4'])
        or (provider==False and transaction_type in ['1', '11', '13'])):
        _text = get_org_name(
                transaction.getparent().find("reporting-org").get("ref")
            )
        _ref = transaction.getparent().find("reporting-org").get("ref")
        _type = transaction.getparent().find("reporting-org").get("type")
        if (_ref is not None) or (_text is not None):
            return {
                'text': _text or _ref,
                'ref': _ref or _text,
                'type': _type
            }

    orgs = transaction.getparent().findall("participating-org[@role='{}']".format(role))
    if len(orgs) == 1:
        _text = get_org_name(
                orgs[0].get('ref'),
                get_narrative_text(orgs[0])
            )
        _ref = orgs[0].get("ref")
        _type = orgs[0].get("type")
        return {
            'text': _text or _ref,
            'ref': _ref or _text,
            'type': _type
        }
    elif len(orgs) > 1:
        return {
            'text': "MULTIPLE",
            'ref': "MULTIPLE",
            'type': "MULTIPLE"
        }
    return {
        'text': "UNKNOWN",
        'ref': "UNKNOWN",
        'type': "UNKNOWN"
    }
예제 #5
0
def process_activity(activity, exchange_rates):
    """
    Main function which reads data from a single `activity`
    lxml ElementTree and extracts only the information we
    need for the visualisation.
    """
    def _get_transaction_sums_commitments(activity, exchange_rates, covid=False):
        """
        Get the sum of commitment transactions (optionally,
        only those transactions tagged as COVID-19 related).
        """
        if covid==True:
            return get_transaction_sums(
                activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][humanitarian-scope/@code='EP-2020-000012-001' or contains(description/narrative/text(), 'COVID-19')]"),
                exchange_rates,
                activity.get("default-currency"))
        return get_transaction_sums(
            # UNCHR uses transaction type 11 (incoming commitment), not 2 (commitment)
            activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11']"),
            exchange_rates,
            activity.get("default-currency"))

    def _get_transaction_sums_disbursements(activity, exchange_rates):
        """
        Get the sum of disbursement transactions.
        """
        return get_transaction_sums(
            activity.xpath("transaction[transaction-type/@code='3' or transaction-type/@code='4']"),
            exchange_rates,
            activity.get("default-currency"))

    def _get_country_region(activity, covid=False):
        """
        Get the list of countries or regions (optionally,
        only from those transactions tagged as COVID-19 related).
        """
        if covid==True:
            return get_country_region(
                [],
                [],
                activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][recipient-country][humanitarian-scope/@code='EP-2020-000012-001' or contains(description/narrative/text(), 'COVID-19')]"),
                activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][recipient-region][humanitarian-scope/@code='EP-2020-000012-001' or contains(description/narrative/text(), 'COVID-19')]"))
        return get_country_region(
            activity.xpath("recipient-country[@vocabulary='1']|recipient-country[not(@vocabulary)]"),
            activity.xpath("recipient-region[@vocabulary='1']|recipient-region[not(@vocabulary)]"),
            activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][recipient-country]"),
            activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][recipient-region]"))

    def _get_sectors(activity):
        """
        Get the list of sectors.
        """
        return get_sector(
            activity.xpath("sector[@vocabulary='1']|sector[not(@vocabulary)]"),
            activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][sector]")
        )

    def _get_humanitarian_development(activity, transaction):
        """
        Add coding as to whether this activity is
        humanitarian; development; a mix (humanitarian
        / development; or unspecified.)
        """
        if (activity == '1') and (not '0' in transaction):
            return "humanitarian"
        elif (activity == '1') and ('0' in transaction):
            return "humanitarian / development"
        elif (activity == '0') and ('1' in transaction):
            return "humanitarian / development"
        elif (activity == '0') and (not '1' in transaction):
            return "development"
        else:
            return "unspecified"

    def _get_finance_types(activity):
        """
        Get the list of finance types.
        """
        return get_finance_type(
            activity.find('default-finance-type'),
            activity.xpath("transaction[transaction-type/@code='2' or transaction-type/@code='11'][finance-type]")
        )

    def _get_covid_matches(activity):
        """
        Add coding regarding which parts of the IATI COVID-19
        Publishing Guidance this activity corresponds to.
        """
        matches = []
        titles = ", ".join(activity.xpath("title/narrative/text()"))
        descriptions = ", ".join(activity.xpath("description/narrative/text()"))
        humanitarian_scopes = ", ".join(activity.xpath("humanitarian-scope/@code"))
        tag = activity.xpath("tag/@code='COVID-19'")
        transaction_descriptions = ", ".join(activity.xpath("transaction/description/narrative/text()"))
        if ("COVID-19" in titles) or ("COVID 19" in titles): matches.append('title')
        if ("COVID-19" in descriptions) or ("COVID 19" in descriptions): matches.append('description')
        if ("EP-2020-000012-001" in humanitarian_scopes): matches.append('GLIDE')
        if ("HCOVD20" in humanitarian_scopes): matches.append('HRP')
        if tag: matches.append('tag')
        if ("COVID-19" in transaction_descriptions) or ("COVID 19" in transaction_descriptions) or ("EP-2020-000012-001" in transaction_descriptions): matches.append('transaction-description')
        return matches

    data = {
        "iatiIdentifier": activity.find('iati-identifier').text.strip(),
        "title": get_narrative(activity.find('title')),
        "reportingOrg": {
            'text': get_narrative(activity.find('reporting-org')),
            'ref': activity.find('reporting-org').get("ref"),
            'type': activity.find('reporting-org').get("type")
        },
        "participatingOrganisation": get_participating_organisations(activity.findall('participating-org')),
        "countriesRegions": _get_country_region(activity),
        "countriesRegionsCOVID": _get_country_region(activity, True),
        "sectors": _get_sectors(activity),
        "financeTypes": _get_finance_types(activity),
        "commitmentsUSD": _get_transaction_sums_commitments(activity, exchange_rates),
        "disbursementsUSD": _get_transaction_sums_disbursements(activity, exchange_rates),
        "budgetsUSD": get_budget_sums(activity.xpath("budget[@type='1']"), activity.xpath("budget[@type='2']"), exchange_rates, activity.get("default-currency")),
        "commitmentsCOVID": _get_transaction_sums_commitments(activity, exchange_rates, True),
        "locations": get_locations(activity.xpath("location")),
        "COVIDComponent": bool(activity.xpath("transaction[humanitarian-scope/@code='EP-2020-000012-001' or contains(description/narrative/text(), 'COVID-19')]")),
        "humanitarianDevelopment": _get_humanitarian_development(activity.get('humanitarian'), set(activity.xpath('transaction/@humanitarian'))),
        "COVIDMatches": _get_covid_matches(activity)
    }
    return data