Example #1
0
    def test_update_company_from_dnb_partial_fields_multiple(
        self,
        formatted_dnb_company,
        adviser_callable,
    ):
        """
        Test that update_company_from_dnb can update a subset of fields.
        """
        duns_number = '123456789'
        company = CompanyFactory(duns_number=duns_number)
        original_company = Company.objects.get(id=company.id)
        adviser = adviser_callable()

        update_company_from_dnb(
            company,
            formatted_dnb_company,
            adviser,
            fields_to_update=['name', 'address'],
        )
        company.refresh_from_db()

        assert company.global_ultimate_duns_number == original_company.global_ultimate_duns_number
        assert company.number_of_employees == original_company.number_of_employees
        assert company.name == formatted_dnb_company['name']
        assert company.address_1 == formatted_dnb_company['address']['line_1']
        assert company.address_2 == formatted_dnb_company['address']['line_2']
        assert company.address_town == formatted_dnb_company['address']['town']
        assert company.address_county == formatted_dnb_company['address'][
            'county']
        assert company.address_postcode == formatted_dnb_company['address'][
            'postcode']
Example #2
0
    def test_rollback(
        self,
        formatted_dnb_company,
        fields,
        expected_fields,
    ):
        """
        Test that rollback_dnb_company_update will roll back all DNB fields.
        """
        with reversion.create_revision():
            company = CompanyFactory(
                duns_number=formatted_dnb_company['duns_number'])

        original_company = Company.objects.get(id=company.id)

        update_company_from_dnb(
            company,
            formatted_dnb_company,
            update_descriptor='foo',
        )

        rollback_dnb_company_update(company, 'foo', fields_to_update=fields)

        company.refresh_from_db()
        for field in expected_fields:
            assert getattr(company, field) == getattr(original_company, field)

        latest_version = Version.objects.get_for_object(company)[0]
        assert latest_version.revision.comment == 'Reverted D&B update from: foo'
Example #3
0
def update_company_from_dnb_data(dnb_company_data,
                                 fields_to_update=None,
                                 update_descriptor=None):
    """
    Update the company with the latest data from dnb-service. This task should be called
    when some other logic interacts with dnb-service to get the company data as the task itself
    will not interact with dnb-service.
    """
    dnb_company = format_dnb_company(dnb_company_data)
    duns_number = dnb_company['duns_number']
    logger.info(f'Updating company with duns_number: {duns_number}')

    try:
        dh_company = Company.objects.get(duns_number=duns_number)
    except Company.DoesNotExist:
        logger.error(
            'Company matching duns_number was not found',
            extra={
                'duns_number': duns_number,
                'dnb_company': dnb_company,
            },
        )
        raise

    if not update_descriptor:
        update_descriptor = 'celery:company_update'

    update_company_from_dnb(
        dh_company,
        dnb_company,
        fields_to_update=fields_to_update,
        update_descriptor=update_descriptor,
    )
    return str(dh_company.pk)
Example #4
0
    def test_update_company_from_dnb_partial_fields_single(
        self,
        formatted_dnb_company,
        adviser_callable,
    ):
        """
        Test that update_company_from_dnb can update a subset of fields.
        """
        duns_number = '123456789'
        company = CompanyFactory(duns_number=duns_number)
        original_company = Company.objects.get(id=company.id)
        adviser = adviser_callable()

        update_company_from_dnb(
            company,
            formatted_dnb_company,
            adviser,
            fields_to_update=['global_ultimate_duns_number'],
        )
        company.refresh_from_db()
        dnb_ultimate_duns = formatted_dnb_company[
            'global_ultimate_duns_number']

        assert company.global_ultimate_duns_number == dnb_ultimate_duns
        assert company.name == original_company.name
        assert company.number_of_employees == original_company.number_of_employees
Example #5
0
def update_from_dnb(model_admin, request, object_id):
    """
    Tool to let admin users update company with a valid `duns_number`
    by pulling fresh data from D&B.

    The company record will be versioned after the update from
    D&B is applied.

    The `pending_dnb_investigation` field will
    be set to False.
    """
    if not model_admin.has_change_permission(request):
        raise PermissionDenied()

    dh_company = model_admin.get_object(request, object_id)

    company_change_page = reverse(
        admin_urlname(model_admin.model._meta, 'change'),
        kwargs={'object_id': dh_company.pk},
    )

    if dh_company is None or dh_company.duns_number is None:
        raise SuspiciousOperation()

    try:
        dnb_company = get_company(dh_company.duns_number, request)

    except DNBServiceInvalidRequestError:
        message = 'No matching company found in D&B database.'
        raise AdminError([message], company_change_page)

    except DNBServiceBaseError:
        message = 'Something went wrong in an upstream service.'
        raise AdminError([message], company_change_page)

    if request.method == 'GET':
        return TemplateResponse(
            request,
            'admin/company/company/update-from-dnb.html',
            {
                **model_admin.admin_site.each_context(request),
                'media':
                model_admin.media,
                'opts':
                model_admin.model._meta,
                'object':
                dh_company,
                'title':
                gettext_lazy('Confirm update from D&B'),
                'diff':
                format_company_diff(dh_company, dnb_company),
            },
        )

    try:
        update_company_from_dnb(dh_company, dnb_company, request.user)
        return HttpResponseRedirect(company_change_page)
    except serializers.ValidationError:
        message = 'Data from D&B did not pass the Data Hub validation checks.'
        raise AdminError([message], company_change_page)
Example #6
0
def _sync_company_with_dnb(
    company_id,
    fields_to_update,
    task,
    update_descriptor,
    retry_failures=True,
):
    dh_company = Company.objects.get(id=company_id)

    try:
        dnb_company = get_company(dh_company.duns_number)
    except DNBServiceError as exc:
        if is_server_error(exc.status_code) and retry_failures:
            raise task.retry(exc=exc, countdown=60)
        raise
    except (DNBServiceConnectionError, DNBServiceTimeoutError) as exc:
        if retry_failures:
            raise task.retry(exc=exc, countdown=60)
        raise

    update_company_from_dnb(
        dh_company,
        dnb_company,
        fields_to_update=fields_to_update,
        update_descriptor=update_descriptor,
    )
 def test_post_dnb_data_invalid(
     self,
     formatted_dnb_company,
 ):
     """
     Tests that ValidationError is raised when data returned by DNB is not valid for saving to a
     Data Hub Company.
     """
     company = CompanyFactory(duns_number='123456789')
     adviser = AdviserFactory()
     formatted_dnb_company['name'] = None
     with pytest.raises(serializers.ValidationError) as excinfo:
         update_company_from_dnb(company, formatted_dnb_company, adviser)
         assert str(excinfo) == 'Data from D&B did not pass the Data Hub validation checks.'
    def test_rollback_error(
        self,
        formatted_dnb_company,
        update_comment,
        error_message,
    ):
        """
        Test that rollback_dnb_company_update will fail with the given error
        message when there is an issue in finding the version to revert to.
        """
        company = CompanyFactory(duns_number=formatted_dnb_company['duns_number'])

        update_company_from_dnb(
            company,
            formatted_dnb_company,
            update_descriptor='foo',
        )

        with pytest.raises(RevisionNotFoundError) as excinfo:
            rollback_dnb_company_update(company, update_comment)
            assert str(excinfo.value) == error_message
Example #9
0
def test_run(s3_stubber, formatted_dnb_company):
    """
    Test that the command successfully rolls back the specified records.
    """
    with reversion.create_revision():
        companies = [
            CompanyFactory(duns_number='123456789'),
            CompanyFactory(duns_number='223456789'),
        ]

    original_companies = {
        company.id: Company.objects.get(id=company.id)
        for company in companies
    }

    update_descriptor = 'foobar'
    # Simulate updating the companies from DNB, which sets a revision with the specified
    # update descriptor
    for company in companies:
        formatted_dnb_company['duns_number'] = company.duns_number
        update_company_from_dnb(
            company,
            formatted_dnb_company,
            update_descriptor=update_descriptor,
        )

    bucket = 'test_bucket'
    object_key = 'test_key'
    csv_content = f"""id
00000000-0000-0000-0000-000000000000
{companies[0].id}
{companies[1].id}
"""

    s3_stubber.add_response(
        'get_object',
        {
            'Body': BytesIO(bytes(csv_content, encoding='utf-8')),
        },
        expected_params={
            'Bucket': bucket,
            'Key': object_key,
        },
    )

    call_command(
        'rollback_dnb_company_updates',
        bucket,
        object_key,
        update_descriptor=update_descriptor,
    )

    # Ensure that the companies are reverted to their previous versions
    for company in companies:
        company.refresh_from_db()
        for field in ALL_DNB_UPDATED_MODEL_FIELDS:
            assert getattr(company,
                           field) == getattr(original_companies[company.id],
                                             field)

        latest_version = Version.objects.get_for_object(company)[0]
        assert latest_version.revision.comment == f'Reverted D&B update from: {update_descriptor}'
Example #10
0
    def test_update_company_from_dnb_all_fields(
        self,
        formatted_dnb_company,
        base_company_dict,
        adviser_callable,
        update_descriptor,
    ):
        """
        Test that update_company_from_dnb will update all fields when the fields
        kwarg is not specified.
        """
        duns_number = '123456789'
        company = CompanyFactory(duns_number=duns_number,
                                 pending_dnb_investigation=True)
        original_company = Company.objects.get(id=company.id)
        adviser = adviser_callable()
        update_company_from_dnb(
            company,
            formatted_dnb_company,
            user=adviser,
            update_descriptor=update_descriptor,
        )
        company.refresh_from_db()
        uk_country = Country.objects.get(iso_alpha2_code='GB')
        assert model_to_dict_company(company) == {
            **base_company_dict,
            'address_1':
            'Unit 10, Ockham Drive',
            'address_2':
            '',
            'address_country':
            uk_country.id,
            'address_county':
            '',
            'address_postcode':
            'UB6 0F2',
            'address_town':
            'GREENFORD',
            'archived_documents_url_path':
            original_company.archived_documents_url_path,
            'business_type':
            original_company.business_type.id,
            'company_number':
            '01261539',
            'created_by':
            original_company.created_by.id,
            'duns_number':
            '123456789',
            'employee_range':
            original_company.employee_range.id,
            'export_experience_category':
            original_company.export_experience_category.id,
            'global_ultimate_duns_number':
            '291332174',
            'id':
            original_company.id,
            'is_number_of_employees_estimated':
            True,
            'modified_by':
            adviser.id if adviser else original_company.modified_by.id,
            'name':
            'FOO BICYCLE LIMITED',
            'number_of_employees':
            260,
            'sector':
            original_company.sector.id,
            'turnover':
            50651895,
            'turnover_range':
            original_company.turnover_range.id,
            'uk_region':
            original_company.uk_region.id,
            'dnb_modified_on':
            now(),
        }

        versions = list(Version.objects.get_for_object(company))
        assert len(versions) == 1
        version = versions[0]

        if update_descriptor:
            assert version.revision.comment == f'Updated from D&B [{update_descriptor}]'
        else:
            assert version.revision.comment == 'Updated from D&B'

        assert version.revision.user == adviser
        if not adviser:
            assert company.modified_on == original_company.modified_on