def handle(self, *args, **options):
        tenant = Tenant.objects.get(pk=options['tenant_id'])

        if tenant:
            credentials = get_credentials('pandadoc', tenant)

            if credentials:
                logger.info('Syncing documents for tenant %s' % tenant.id)
                # Get all current documents.
                tenant_documents = Document.objects.filter(tenant=tenant)

                url = 'https://api.pandadoc.com/public/v1/documents'
                # Get all documents from PandaDoc.
                response = send_get_request(url, credentials)

                if response.status_code == 200:
                    documents = response.json().get('results')

                    for document in documents:
                        document_id = document.get('id')

                        # Document doesn't exist (so something probably went wrong while creating the quote).
                        if not tenant_documents.filter(document_id=document_id):
                            details_url = url + '/%s/details' % document_id
                            response = send_get_request(details_url, credentials)

                            if response.status_code == 200:
                                deal_id = response.json().get('metadata').get('deal')

                                if deal_id:
                                    deal = Deal.objects.get(pk=deal_id)

                                    document = Document.objects.create(
                                        contact=deal.contact,
                                        deal=deal,
                                        document_id=document_id,
                                        tenant=tenant,
                                    )

                                    self.imported_documents_count += 1
                            else:
                                message = '[PandaDoc] Something went wrong while syncing document %s: ' % document_id
                                message = message + response.text
                                logger.warning(message)
                else:
                    message = '[PandaDoc] Something went while syncing documents: ' + response.json()
                    logger.warning(message)
            else:
                message = '[PandaDoc] Tenant %s doesn\'t have PandaDoc credentials' % options['tenant_id']
                logger.warning(message)

            logger.info('%s documents have been imported' % self.imported_documents_count)
        else:
            logger.error('Please enter a valid tenant')
Ejemplo n.º 2
0
    def get(self, request, contact_id, format=None):
        """
        List all Moneybird estimates.
        """
        credentials = get_credentials('moneybird')

        url = 'https://moneybird.com/api/v2/%s/estimates' % credentials.integration_context.get('administration_id')

        response = send_get_request(url, credentials)

        data = response.json()

        return Response({'estimates': data})
Ejemplo n.º 3
0
    def get(self, request, contact_id, format=None):
        """
        List all Moneybird estimates.
        """
        credentials = get_credentials('moneybird')

        url = 'https://moneybird.com/api/v2/%s/estimates' % credentials.integration_context.get('administration_id')

        response = send_get_request(url, credentials)

        data = response.json()

        return Response({'estimates': data})
Ejemplo n.º 4
0
    def get(self, request, contact_id, format=None):
        documents = Document.objects.filter(contact=self.kwargs['contact_id'])
        temp_documents = []

        credentials = get_credentials(IntegrationDetails.PANDADOC)

        for document in documents:
            url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document.document_id

            response = send_get_request(url, credentials)

            data = response.json()

            if data.get('id'):
                temp_documents.append(data)
            else:
                # No details could be retreived, so it's probably been deleted in PandaDoc.
                document.delete()

        return Response({'documents': temp_documents})
Ejemplo n.º 5
0
    def get(self, request, contact_id, format=None):
        """
        List all PandaDoc documents.
        """
        documents = Document.objects.filter(contact=self.kwargs['contact_id'])
        temp_documents = []

        credentials = get_credentials('pandadoc')

        for document in documents:
            url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document.document_id

            response = send_get_request(url, credentials)

            data = response.json()

            if data.get('id'):
                temp_documents.append(data)
            else:
                # No details could be retreived, so it's probably been deleted in PandaDoc.
                document.delete()

        return Response({'documents': temp_documents})
Ejemplo n.º 6
0
    def get(self, request, deal_id, format=None):
        """
        List all PandaDoc documents.
        """
        documents = Document.objects.filter(deal_id=deal_id)
        temp_documents = []

        credentials = get_credentials('pandadoc')

        for document in documents:
            url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document.document_id

            response = send_get_request(url, credentials)

            data = response.json()

            if data.get('id'):
                temp_documents.append(data)
            else:
                # No details could be retreived, so it's probably been deleted in PandaDoc.
                document.delete()

        return Response({'documents': temp_documents})
Ejemplo n.º 7
0
def import_moneybird_contacts(tenant_id):
    importing = True
    page = 1

    tenant = Tenant.objects.get(pk=tenant_id)
    # Can't retreive tenant from request here, so get the tenant.
    credentials = get_credentials('moneybird', tenant)

    administration_id = credentials.integration_context.get(
        'administration_id')

    # New tenants have this account status, but older tenants might not.
    account_status, status_created = AccountStatus.objects.get_or_create(
        name='Customer', tenant=tenant)

    base_url = 'https://moneybird.com/api/v2/%s/contacts?page=%s&per_page=100'

    while importing:
        url = base_url % (administration_id, page)
        response = send_get_request(url, credentials)

        data = response.json()

        if data:
            for contact_data in data:
                # For every field we want to fill we do the following:
                # 1. Setup a dict with the information.
                # 2. Retrieve all objects with that info.
                # 3. If no object exists, create a new one (and add to set for related objects).
                try:
                    with transaction.atomic():
                        contact = None
                        first_name = contact_data.get('firstname')
                        last_name = contact_data.get('lastname', '')

                        if first_name:
                            contact_dict = {
                                'first_name': first_name,
                                'last_name': last_name,
                                'tenant': tenant,
                                'is_deleted': False
                            }
                            # Since we have the possibility to resync we want to update
                            # contacts that might already exist.
                            contact = Contact.objects.filter(
                                **contact_dict).last()

                            if not contact:
                                contact = Contact.objects.create(
                                    **contact_dict)

                        company = contact_data.get('company_name')

                        if company:
                            account_dict = {
                                'name': company,
                                'status': account_status,
                                'tenant': tenant,
                                'is_deleted': False
                            }
                            account = Account.objects.filter(
                                **account_dict).last()

                            if not account:
                                account = Account.objects.create(
                                    **account_dict)

                            if contact:
                                # Contacts and accounts are linked through functions.
                                Function.objects.get_or_create(account=account,
                                                               contact=contact)

                        if contact:
                            # Save all contact info to the contact if there is one.
                            contact_object = contact
                        else:
                            # Otherwise use the account.
                            contact_object = account

                        invoices_email = contact_data.get(
                            'send_invoices_to_email')
                        estimates_email = contact_data.get(
                            'send_estimates_to_email')
                        phone = contact_data.get('phone')
                        address = contact_data.get('address1')
                        alternate_address = contact_data.get('address2')

                        if invoices_email:
                            invoices_email_dict = {
                                'email_address': invoices_email,
                                'tenant': tenant,
                            }
                            invoices_email_address = contact_object.email_addresses.filter(
                                **invoices_email_dict)

                            if not invoices_email_address.last():
                                invoices_email_address = EmailAddress.objects.create(
                                    **invoices_email_dict)
                                contact_object.email_addresses.add(
                                    invoices_email_address)

                        if estimates_email and not invoices_email == estimates_email:
                            # No point in adding two of the same email addresses.
                            estimates_email_dict = {
                                'email_address': estimates_email,
                                'tenant': tenant,
                            }
                            estimates_email_address = contact_object.email_addresses.filter(
                                **estimates_email_dict)

                            if not estimates_email_address.last():
                                estimates_email_address = EmailAddress.objects.create(
                                    **estimates_email_dict)
                                contact_object.email_addresses.add(
                                    estimates_email_address)

                        if phone:
                            phone_number_dict = {
                                'number': phone,
                                'tenant': tenant,
                            }
                            phone_number = contact_object.phone_numbers.filter(
                                **phone_number_dict).last()

                            if not phone_number:
                                phone_number = PhoneNumber.objects.create(
                                    **phone_number_dict)
                                contact_object.phone_numbers.add(phone_number)

                        if address:
                            postal_code = contact_data.get('zipcode')
                            city = contact_data.get('city')
                            country = contact_data.get('country')

                            address_dict = {
                                'address': address,
                                'postal_code': postal_code,
                                'city': city,
                                'country': country,
                                'tenant': tenant,
                            }

                            address = Address.objects.filter(
                                **address_dict).last()

                            if not address:
                                address = Address.objects.create(
                                    **address_dict)
                                contact_object.addresses.add(address)

                            if alternate_address:
                                address_dict = ({
                                    'address': alternate_address,
                                    'country': country,
                                    'tenant': tenant,
                                })

                                alternate_address = Address.objects.filter(
                                    **address_dict).last()

                                if not alternate_address:
                                    alternate_address = Address.objects.create(
                                        **address_dict)
                                    contact_object.addresses.add(
                                        alternate_address)

                        contact_object.save()
                except Exception as e:
                    logger.error(e)

            # Increment the page so we can check for more contacts.
            page += 1
        else:
            importing = False
Ejemplo n.º 8
0
    def get(self, request, *args, **kwargs):
        template = EmailTemplate.objects.get(pk=kwargs.get('template_id'))
        lookup = {'user': self.request.user}
        errors = {}

        if 'account_id' in self.request.GET:
            try:
                account = Account.objects.get(pk=self.request.GET.get('account_id'))
            except Account.DoesNotExist:
                pass
            else:
                lookup.update({'account': account})

        if 'contact_id' in self.request.GET:
            try:
                contact = Contact.objects.get(pk=self.request.GET.get('contact_id'))
            except Contact.DoesNotExist:
                pass
            else:
                lookup.update({'contact': contact})
                functions = contact.functions.all()
                if len(functions) == 1:
                    try:
                        account = Account.objects.get(pk=functions[0].account_id)
                    except Account.DoesNotExist:
                        pass
                    else:
                        lookup.update({'account': account})

        if 'document_id' in self.request.GET:
            credentials = get_credentials('pandadoc')

            if credentials:
                error_message = None
                document_id = self.request.GET.get('document_id')
                recipient = self.request.GET.get('recipient_email')

                details_url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document_id

                response = send_get_request(details_url, credentials)

                if response.status_code == 200:
                    # Only documents with the 'draft' status can be set to sent.
                    if response.json().get('status') == 'document.draft':
                        # Set the status of the document to 'sent' so we can create a view session.
                        send_url = 'https://api.pandadoc.com/public/v1/documents/%s/send' % document_id
                        send_params = {'silent': True}
                        response = send_post_request(send_url, credentials, send_params)

                        if response.status_code != 200:
                            error_message = 'Something went wrong while setting up the PandaDoc sign URL.'

                    metadata = response.json().get('metadata')

                    if metadata and metadata.get('account'):
                        account_id = metadata.get('account')

                        try:
                            account = Account.objects.get(pk=account_id)
                        except Account.DoesNotExist:
                            pass
                        else:
                            lookup.update({'account': account})

                    # Document has been 'sent' so create the session.
                    session_url = 'https://api.pandadoc.com/public/v1/documents/%s/session' % document_id
                    year = 60 * 60 * 24 * 365
                    session_params = {'recipient': recipient, 'lifetime': year}

                    response = send_post_request(session_url, credentials, session_params)

                    if response.status_code == 201:
                        sign_url = 'https://app.pandadoc.com/s/%s' % response.json().get('id')
                        lookup.update({'document': {'sign_url': sign_url}})
                    else:
                        error_message = ('The PandaDoc sign URL could not be created \
                                          because the recipient isn\'t correct')
                else:
                    error_message = 'The document doesn\'t seem to be valid.'

                if error_message:
                    errors.update({
                        'document': error_message
                    })

        if 'emailaccount_id' in self.request.GET:
            try:
                emailaccount = EmailAccount.objects.get(pk=self.request.GET.get('emailaccount_id'))
            except EmailAccount.DoesNotExist:
                pass
            else:
                lookup.get('user').current_email_address = emailaccount.email_address

        # Setup regex to find custom variables
        search_regex = '\[\[ custom\.(.*?) \]\]'
        # Find all occurrences.
        search_result = re.findall(search_regex, template.body_html)

        if search_result:
            for custom_variable in search_result:
                public = None

                try:
                    # Try to split to see if it's a public variable
                    variable, public = custom_variable.split('.')
                except ValueError:
                    # Not a public variable, so .split raises an error
                    variable = custom_variable

                if public:
                    template_variable = TemplateVariable.objects.filter(
                        name__iexact=variable,
                        is_public=True
                    )
                else:
                    template_variable = TemplateVariable.objects.filter(
                        name__iexact=variable,
                        owner=get_current_user()
                    )

                if template_variable:
                    # find = '\[\[ custom.' + custom_variable + '(\s)?\]\]'
                    find = re.compile('\[\[ custom\.' + custom_variable + ' \]\]')
                    replace = template_variable.first().text

                    template.body_html = re.sub(find, replace, template.body_html, 1)

        # Ugly hack to make parsing of new template brackets style work
        parsed_template = Template(template.body_html.replace('[[', '{{').replace(']]', '}}')).render(Context(lookup))
        parsed_subject = Template(template.subject.replace('[[', '{{').replace(']]', '}}')).render(Context(lookup))

        # Make sure HTML entities are displayed correctly
        html_parser = HTMLParser.HTMLParser()
        parsed_subject = html_parser.unescape(parsed_subject)

        attachments = []

        for attachment in template.attachments.all():
            # Get attachment name
            name = get_attachment_filename_from_url(attachment.attachment.name)

            attachments.append({
                'id': attachment.id,
                'name': name,
            })

        return HttpResponse(anyjson.serialize({
            'template': parsed_template,
            'template_subject': parsed_subject,
            'attachments': attachments,
            'errors': errors,
        }), content_type='application/json')
Ejemplo n.º 9
0
    def send_moneybird_contact(self,
                               validated_data,
                               instance,
                               credentials,
                               original_data=None):
        administration_id = credentials.integration_context.get(
            'administration_id')
        contact_url = 'https://moneybird.com/api/v2/%s/contacts'

        if original_data:
            full_name = original_data.get('full_name')
        else:
            full_name = instance.full_name

        search_url = (contact_url + '?query=%s') % (administration_id,
                                                    full_name)
        response = send_get_request(search_url, credentials)
        data = response.json()

        patch = False
        params = {}

        if data:
            data = data[0]
            moneybird_id = data.get('id')
            post_url = (contact_url + '/%s') % (administration_id,
                                                moneybird_id)

            params = {
                'id': moneybird_id,
            }

            # Existing Moneybird contact found so we want to PATCH.
            patch = True
        else:
            post_url = contact_url % administration_id

        if 'first_name' in validated_data:
            params.update({'firstname': validated_data.get('first_name')})

        if 'last_name' in validated_data:
            params.update({'lastname': validated_data.get('last_name')})

        accounts = instance.accounts.all()

        if 'accounts' in validated_data and len(accounts) == 1:
            params.update({'company_name': accounts[0].name})

        if 'phone_numbers' in validated_data:
            phone_numbers = []

            for validated_number in validated_data.get('phone_numbers'):
                for phone_number in instance.phone_numbers.all():
                    if validated_number.get('number') == phone_number.number:
                        phone_numbers.append(phone_number)
                        break

            if phone_numbers:
                params.update({'phone': phone_numbers[0].number})

        if 'addresses' in validated_data:
            addresses = []

            for validated_address in validated_data.get('addresses'):
                for address in instance.addresses.all():
                    if validated_address.get('address') == address.address:
                        addresses.append(address)
                        break

            if addresses:
                address = addresses[0]
                params.update({
                    'address1': address.get('address'),
                    'zipcode': address.get('postal_code'),
                    'city': address.get('city'),
                    'country': address.get('country'),
                })

        if 'email_addresses' in validated_data:
            validated_email_addresses = validated_data.get('email_addresses')
            original_email_address = original_data.get(
                'original_email_address')

            if len(validated_email_addresses) == 1 and original_email_address:
                if data:
                    invoices_email = data.get('send_invoices_to_email')
                    estimates_email = data.get('send_estimates_to_email')
                    validated_email_address = validated_email_addresses[0].get(
                        'email_address')

                    if invoices_email == estimates_email and invoices_email == original_email_address:
                        params.update({
                            'send_invoices_to_email':
                            validated_email_address,
                            'send_estimates_to_email':
                            validated_email_address,
                        })
                    elif invoices_email == original_email_address:
                        params.update({
                            'send_invoices_to_email':
                            validated_email_address,
                        })
                    elif estimates_email == original_email_address:
                        params.update({
                            'send_estimates_to_email':
                            validated_email_address,
                        })

        params = {'contact': params, 'administration_id': administration_id}

        response = send_post_request(post_url, credentials, params, patch,
                                     True)
Ejemplo n.º 10
0
    def send_moneybird_contact(self, validated_data, instance, credentials, original_data=None):
        administration_id = credentials.integration_context.get('administration_id')
        contact_url = 'https://moneybird.com/api/v2/%s/contacts'

        if original_data:
            full_name = original_data.get('full_name')
        else:
            full_name = instance.full_name

        search_url = (contact_url + '?query=%s') % (administration_id, full_name)
        response = send_get_request(search_url, credentials)
        data = response.json()

        patch = False
        params = {}

        if data:
            data = data[0]
            moneybird_id = data.get('id')
            post_url = (contact_url + '/%s') % (administration_id, moneybird_id)

            params = {
                'id': moneybird_id,
            }

            # Existing Moneybird contact found so we want to PATCH.
            patch = True
        else:
            post_url = contact_url % administration_id

        if 'first_name' in validated_data:
            params.update({'firstname': validated_data.get('first_name')})

        if 'last_name' in validated_data:
            params.update({'lastname': validated_data.get('last_name')})

        accounts = instance.accounts.all()

        if 'accounts' in validated_data and len(accounts) == 1:
            params.update({'company_name': accounts[0].name})

        if 'phone_numbers' in validated_data:
            phone_numbers = []

            for validated_number in validated_data.get('phone_numbers'):
                for phone_number in instance.phone_numbers.all():
                    if validated_number.get('number') == phone_number.number:
                        phone_numbers.append(phone_number)
                        break

            if phone_numbers:
                params.update({'phone': phone_numbers[0].number})

        if 'addresses' in validated_data:
            addresses = []

            for validated_address in validated_data.get('addresses'):
                for address in instance.addresses.all():
                    if validated_address.get('address') == address.address:
                        addresses.append(address)
                        break

            if addresses:
                address = addresses[0]
                params.update({
                    'address1': address.address,
                    'zipcode': address.postal_code,
                    'city': address.city,
                    'country': address.country,
                })

        if 'email_addresses' in validated_data:
            original_email_address = None
            validated_email_addresses = validated_data.get('email_addresses')

            if original_data:
                original_email_address = original_data.get('original_email_address')

            if len(validated_email_addresses) == 1:
                validated_email_address = validated_email_addresses[0].get('email_address')

                if data and original_email_address:
                    invoices_email = data.get('send_invoices_to_email')
                    estimates_email = data.get('send_estimates_to_email')

                    if invoices_email == estimates_email and invoices_email == original_email_address:
                        params.update({
                            'send_invoices_to_email': validated_email_address,
                            'send_estimates_to_email': validated_email_address,
                        })
                    elif invoices_email == original_email_address:
                        params.update({
                            'send_invoices_to_email': validated_email_address,
                        })
                    elif estimates_email == original_email_address:
                        params.update({
                            'send_estimates_to_email': validated_email_address,
                        })
                else:
                    params.update({
                        'send_invoices_to_email': validated_email_address,
                        'send_estimates_to_email': validated_email_address,
                    })

        params = {
            'contact': params,
            'administration_id': administration_id
        }

        response = send_post_request(post_url, credentials, params, patch, True)
Ejemplo n.º 11
0
    def get(self, request, *args, **kwargs):
        template = EmailTemplate.objects.get(pk=kwargs.get('template_id'))
        lookup = {'user': self.request.user}
        errors = {}

        if 'account_id' in self.request.GET:
            try:
                account = Account.objects.get(
                    pk=self.request.GET.get('account_id'))
            except Account.DoesNotExist:
                pass
            else:
                lookup.update({'account': account})

        if 'contact_id' in self.request.GET:
            try:
                contact = Contact.objects.get(
                    pk=self.request.GET.get('contact_id'))
            except Contact.DoesNotExist:
                pass
            else:
                lookup.update({'contact': contact})
                functions = contact.functions.all()
                if len(functions) == 1:
                    try:
                        account = Account.objects.get(
                            pk=functions[0].account_id)
                    except Account.DoesNotExist:
                        pass
                    else:
                        lookup.update({'account': account})

        if 'document_id' in self.request.GET:
            credentials = get_credentials('pandadoc')

            if credentials:
                error_message = None
                document_id = self.request.GET.get('document_id')
                recipient = self.request.GET.get('recipient_email')

                details_url = 'https://api.pandadoc.com/public/v1/documents/%s/details' % document_id

                response = send_get_request(details_url, credentials)

                if response.status_code == 200:
                    # Only documents with the 'draft' status can be set to sent.
                    if response.json().get('status') == 'document.draft':
                        # Set the status of the document to 'sent' so we can create a view session.
                        send_url = 'https://api.pandadoc.com/public/v1/documents/%s/send' % document_id
                        send_params = {'silent': True}
                        response = send_post_request(send_url, credentials,
                                                     send_params)

                        if response.status_code != 200:
                            error_message = 'Something went wrong while setting up the PandaDoc sign URL.'

                    metadata = response.json().get('metadata')

                    if metadata and metadata.get('account'):
                        account_id = metadata.get('account')

                        try:
                            account = Account.objects.get(pk=account_id)
                        except Account.DoesNotExist:
                            pass
                        else:
                            lookup.update({'account': account})

                    # Document has been 'sent' so create the session.
                    session_url = 'https://api.pandadoc.com/public/v1/documents/%s/session' % document_id
                    year = 60 * 60 * 24 * 365
                    session_params = {'recipient': recipient, 'lifetime': year}

                    response = send_post_request(session_url, credentials,
                                                 session_params)

                    if response.status_code == 201:
                        sign_url = 'https://app.pandadoc.com/s/%s' % response.json(
                        ).get('id')
                        lookup.update({'document': {'sign_url': sign_url}})
                    else:
                        error_message = (
                            'The PandaDoc sign URL could not be created \
                                          because the recipient isn\'t correct'
                        )
                else:
                    error_message = 'The document doesn\'t seem to be valid.'

                if error_message:
                    errors.update({'document': error_message})

        if 'emailaccount_id' in self.request.GET:
            try:
                emailaccount = EmailAccount.objects.get(
                    pk=self.request.GET.get('emailaccount_id'))
            except EmailAccount.DoesNotExist:
                pass
            else:
                lookup.get(
                    'user').current_email_address = emailaccount.email_address

        # Setup regex to find custom variables
        search_regex = '\[\[ custom\.(.*?) \]\]'
        # Find all occurrences.
        search_result = re.findall(search_regex, template.body_html)

        if search_result:
            for custom_variable in search_result:
                public = None

                try:
                    # Try to split to see if it's a public variable
                    variable, public = custom_variable.split('.')
                except ValueError:
                    # Not a public variable, so .split raises an error
                    variable = custom_variable

                if public:
                    template_variable = TemplateVariable.objects.filter(
                        name__iexact=variable, is_public=True)
                else:
                    template_variable = TemplateVariable.objects.filter(
                        name__iexact=variable, owner=get_current_user())

                if template_variable:
                    # find = '\[\[ custom.' + custom_variable + '(\s)?\]\]'
                    find = re.compile('\[\[ custom\.' + custom_variable +
                                      ' \]\]')
                    replace = template_variable.first().text

                    template.body_html = re.sub(find, replace,
                                                template.body_html, 1)

        # Ugly hack to make parsing of new template brackets style work
        parsed_template = Template(
            template.body_html.replace('[[', '{{').replace(']]', '}}')).render(
                Context(lookup))
        parsed_subject = Template(
            template.subject.replace('[[', '{{').replace(']]', '}}')).render(
                Context(lookup))

        # Make sure HTML entities are displayed correctly
        html_parser = HTMLParser.HTMLParser()
        parsed_subject = html_parser.unescape(parsed_subject)

        attachments = []

        for attachment in template.attachments.all():
            # Get attachment name
            name = get_attachment_filename_from_url(attachment.attachment.name)

            attachments.append({
                'id': attachment.id,
                'name': name,
            })

        return HttpResponse(anyjson.serialize({
            'template': parsed_template,
            'template_subject': parsed_subject,
            'attachments': attachments,
            'errors': errors,
        }),
                            content_type='application/json')
Ejemplo n.º 12
0
def import_moneybird_contacts(tenant_id):
    importing = True
    page = 1

    tenant = Tenant.objects.get(pk=tenant_id)
    # Can't retreive tenant from request here, so get the tenant.
    credentials = get_credentials('moneybird', tenant)

    administration_id = credentials.integration_context.get('administration_id')

    # New tenants have this account status, but older tenants might not.
    account_status, status_created = AccountStatus.objects.get_or_create(name='Customer', tenant=tenant)

    base_url = 'https://moneybird.com/api/v2/%s/contacts?page=%s&per_page=100'

    while importing:
        url = base_url % (administration_id, page)
        response = send_get_request(url, credentials)

        data = response.json()

        if data:
            for contact_data in data:
                # For every field we want to fill we do the following:
                # 1. Setup a dict with the information.
                # 2. Retrieve all objects with that info.
                # 3. If no object exists, create a new one (and add to set for related objects).
                try:
                    with transaction.atomic():
                        contact = None
                        first_name = contact_data.get('firstname')
                        last_name = contact_data.get('lastname', '')

                        if first_name:
                            contact_dict = {
                                'first_name': first_name,
                                'last_name': last_name,
                                'tenant': tenant,
                                'is_deleted': False
                            }
                            # Since we have the possibility to resync we want to update
                            # contacts that might already exist.
                            contact = Contact.objects.filter(**contact_dict).last()

                            if not contact:
                                contact = Contact.objects.create(**contact_dict)

                        company = contact_data.get('company_name')

                        if company:
                            account_dict = {
                                'name': company,
                                'status': account_status,
                                'tenant': tenant,
                                'is_deleted': False
                            }
                            account = Account.objects.filter(**account_dict).last()

                            if not account:
                                account = Account.objects.create(**account_dict)

                            if contact:
                                # Contacts and accounts are linked through functions.
                                Function.objects.get_or_create(account=account, contact=contact)

                        if contact:
                            # Save all contact info to the contact if there is one.
                            contact_object = contact
                        else:
                            # Otherwise use the account.
                            contact_object = account

                        invoices_email = contact_data.get('send_invoices_to_email')
                        estimates_email = contact_data.get('send_estimates_to_email')
                        phone = contact_data.get('phone')
                        address = contact_data.get('address1')
                        alternate_address = contact_data.get('address2')

                        if invoices_email:
                            invoices_email_dict = {
                                'email_address': invoices_email,
                                'tenant': tenant,
                            }
                            invoices_email_address = contact_object.email_addresses.filter(**invoices_email_dict)

                            if not invoices_email_address.last():
                                invoices_email_address = EmailAddress.objects.create(**invoices_email_dict)
                                contact_object.email_addresses.add(invoices_email_address)

                        if estimates_email and not invoices_email == estimates_email:
                            # No point in adding two of the same email addresses.
                            estimates_email_dict = {
                                'email_address': estimates_email,
                                'tenant': tenant,
                            }
                            estimates_email_address = contact_object.email_addresses.filter(**estimates_email_dict)

                            if not estimates_email_address.last():
                                estimates_email_address = EmailAddress.objects.create(**estimates_email_dict)
                                contact_object.email_addresses.add(estimates_email_address)

                        if phone:
                            phone_number_dict = {
                                'number': phone,
                                'tenant': tenant,
                            }
                            phone_number = contact_object.phone_numbers.filter(**phone_number_dict).last()

                            if not phone_number:
                                phone_number = PhoneNumber.objects.create(**phone_number_dict)
                                contact_object.phone_numbers.add(phone_number)

                        if address:
                            postal_code = contact_data.get('zipcode')
                            city = contact_data.get('city')
                            country = contact_data.get('country')

                            address_dict = {
                                'address': address,
                                'postal_code': postal_code,
                                'city': city,
                                'country': country,
                                'tenant': tenant,
                            }

                            address = Address.objects.filter(**address_dict).last()

                            if not address:
                                address = Address.objects.create(**address_dict)
                                contact_object.addresses.add(address)

                            if alternate_address:
                                address_dict = ({
                                    'address': alternate_address,
                                    'country': country,
                                    'tenant': tenant,
                                })

                                alternate_address = Address.objects.filter(**address_dict).last()

                                if not alternate_address:
                                    alternate_address = Address.objects.create(**address_dict)
                                    contact_object.addresses.add(alternate_address)

                        contact_object.save()
                except Exception as e:
                    logger.error(e)

            # Increment the page so we can check for more contacts.
            page += 1
        else:
            importing = False