Пример #1
0
def run(api_key, development, confirmed, limit=100):
    api = CloseIO_API(api_key, development=development)

    # loop through existing leads with multiple addresses

    LEADS_QUERY_WITH_MULTIPLE_ADDRESSES = "addresses > 1 sort:activities"
    has_more = True

    while has_more:
        resp = api.get('lead',
                       data={
                           'query': LEADS_QUERY_WITH_MULTIPLE_ADDRESSES,
                           '_fields': 'id,addresses',
                           '_limit': limit,
                       })

        leads = resp['data']

        for lead in leads:
            if len(lead['addresses']) < 2:
                logging.warning("unexpected result: %s", lead)
                continue  # this shouldn't happen based on the search query, but just to be safe...
            if confirmed:
                api.put('lead/' + lead['id'],
                        data={'addresses': lead['addresses'][:1]})
            logging.info("removed %d extra address(es) for %s\n%s" % (len(
                lead['addresses'][1:]), lead['id'], lead['addresses'][1:]))

        has_more = resp['has_more']

        time.sleep(
            2
        )  # give the search indexer some time to catch up with the changes
Пример #2
0
def export_total_talk_time_per_lead_for_each_org():
    """For each api key given, upload a CSV to dropbox of the total talk
    time per lead per user for an organization. 
    """
    global leads
    global calls_per_lead
    global user_ids_to_names
    global api
    for api_key in os.environ.get('CLOSE_API_KEYS').split(','):
        ## Initiate Close API
        leads = []
        calls_per_lead = []
        user_ids_to_names = {}
        api = CloseIO_API(api_key.strip())
        try:
            org = api.get('me')['organizations'][0]
            org_name = org['name'].replace('/', ' ')
            org_id = org['id']
            org_memberships = api.get(
                'organization/' + org['id'],
                params={'_fields': 'memberships,inactive_memberships'})
            user_ids_to_names = {
                k['user_id']: k['user_full_name']
                for k in org_memberships['memberships'] +
                org_memberships['inactive_memberships']
            }
        except APIError as e:
            print(f'Failed to pull org data because {str(e)} for {api_key}')
            continue

        try:
            name_keys = [
                f'{v} Total Talk Time' for v in user_ids_to_names.values()
            ]
            name_keys = sorted(name_keys)
            print(f'Getting calls for {org_name}')
            final_calls_per_lead = _get_call_duration_per_lead()
            final_calls_per_lead = sorted(final_calls_per_lead,
                                          key=itemgetter('Lead Name'))
        except Exception as e:
            print(f'Failed to pull calls for {org_name} because {str(e)}')
            continue

        ordered_keys = ['Lead ID', 'Lead Name', 'Total Talk Time'] + name_keys
        output = io.StringIO()
        writer = csv.DictWriter(output, ordered_keys)
        writer.writeheader()
        writer.writerows(final_calls_per_lead)
        csv_output = output.getvalue().encode('utf-8')

        file_name = f"{org_name}/{org_name} Total Talk Time {datetime.today().strftime('%Y-%m-%d')}.csv"
        upload_to_dropbox(file_name, csv_output)
Пример #3
0
def room_message_hook():
    data = json.loads(request.data)
    message = data['item']['message']['message']
    room_id = data['item']['room']['id']

    matched = re.match(LEAD_REGEXP, message)
    if matched:
        lead_id = matched.group(1)
        api = CloseIO_API(get_api_key(tenant.id))
        lead = get_lead_info(api, lead_id)
        if lead:
            orga = get_orga_info(api, lead['organization_id'])
            notification = render_template('lead.html', lead=lead, orga=orga)
            room_client = RoomClient(room_id)
            room_client.send_notification(notification)
    return '', 204
Пример #4
0
args = parser.parse_args()

"""
Detect duplicate leads and merge them.

Duplicate criteria:
- Case insensitive exact match by Company Name

Priority (how to choose 'Destination lead'):
- Prefers leads with Opportunities over ones without.
- If both or neither have opportunities, prefer leads with desired_status specified below.
"""

desired_status = 'open' # capitalization doesn't matter

api = CloseIO_API(args.api_key, development=args.development)
has_more = True
offset = 0
last_lead = None
total_merged = 0

while has_more:
    leads_merged_this_page = 0

    # Get a page of leads
    resp = api.get('lead', data={
        'query': 'sort:display_name',
        '_skip': offset,
        '_fields': 'id,display_name,name,status_label,opportunities,custom'
    })
    leads = resp['data']
Пример #5
0
)
parser.add_argument(
    '--lead-id',
    '-l',
    help=
    'Use this field if you want to narrow your search to a specific lead_id',
)
parser.add_argument(
    '--user-id',
    '-u',
    help=
    'Use this field if you want to narrow your search to changes done by a specific user',
)
args = parser.parse_args()

api = CloseIO_API(args.api_key)
org_id = api.get('me')['organizations'][0]['id']
org = api.get(
    'organization/' + org_id,
    params={
        '_fields':
        'id,name,memberships,inactive_memberships,lead_custom_fields'
    },
)
org_name = org['name'].replace('/', "")
org_memberships = org['memberships'] + org['inactive_memberships']
try:
    custom_field_name = [
        i for i in org['lead_custom_fields'] if i['id'] == args.custom_field
    ][0]['name']
except IndexError as e:
def run(api_key, confirmed, development=False, use_existing_contact=False, new_contact_name='', phones_custom_field='all phones', emails_custom_field='all emails'):
    """
    After an import from a different CRM, for all leads, move emails and phones that were put in
    in a lead custom field to the lead's first contact (if--use_existing_contact flag was used)
    or create a new contact.
    """

    print 'confirmed:', `confirmed`
    print 'phones_custom_field:', `phones_custom_field`
    print 'emails_custom_field:', `emails_custom_field`
    print 'use_existing_contact:', `use_existing_contact`

    api = CloseIO_API(api_key, development=development)
    has_more = True
    offset = 0

    while has_more:

        # Get a page of leads
        resp = api.get('lead', data={
            'query': '"custom.Source CRM":* not "custom.Migration completed":* sort:created',
            '_skip': offset,
            '_fields': 'id,display_name,name,contacts,custom',
        })
        leads = resp['data']

        for lead in leads:
            contacts = lead['contacts']
            custom = lead['custom']

            company_emails = custom.get(emails_custom_field, '')
            company_phones = custom.get(phones_custom_field, '')

            if not company_phones and not company_emails:
                continue

            if company_emails :
                if company_emails.startswith('["'):
                    company_emails = company_emails[2:-2].split('", "')
                else:
                    company_emails = [company_emails]

            if company_phones:
                if company_phones.startswith('["'):
                    company_phones = company_phones[2:-2].split('", "')
                else:
                    company_phones = [company_phones]

            if contacts and use_existing_contact:
                contact = contacts[0]
            else:
                contact = {
                    'lead_id': lead['id'],
                    'phones': [],
                    'emails': []
                }
                if new_contact_name:
                    contact['name'] = new_contact_name


            for pn in company_phones:
                contact['phones'].append({ 'type': 'office', 'phone': pn })
            for e in company_emails:
                contact['emails'].append({ 'type': 'office', 'email': e })

            print 'Lead:', lead['id'], lead['name'].encode('utf8')
            print 'Emails:', `custom.get(emails_custom_field)`, ' => ', `company_emails`
            print 'Phones:', `custom.get(phones_custom_field)`, ' => ', `company_phones`

            try:
                if contact.get('id'):
                    print 'Updating an existing contact', contact['id']
                    if confirmed:
                        api.put('contact/%s' % contact['id'], data={
                            'phones': contact['phones'],
                            'emails': contact['emails'],
                        })
                else:
                    print 'Creating a new contact'
                    if confirmed:
                        api.post('contact', data=contact)
                print 'Payload:', contact
                if confirmed:
                    api.put('lead/%s' % lead['id'], data={
                        'custom.Migration completed': 'Yes'
                    })
            except APIError as e:
                print e
                print 'Payload:', contact
                if confirmed:
                    api.put('lead/%s' % lead['id'], data={
                        'custom.Migration completed': 'skipped'
                    })

            print ''

        if not confirmed:
            # If we don't actually update the "Migration completed" custom field,
            # we need to paginate
            offset += len(leads)

        has_more = resp['has_more']

    print 'Done'
Пример #7
0
def run_import(api_key, list_type):

	import_status = ''
	api = CloseIO_API(api_key)

	# Try API Key
	try:
		test_api_key = api.get('me')
	except:
		import_status = 'bad_api_key'
		return import_status

	### Get Close.io Custom Fields
	print "...Getting Current Custom Fields"
	current_custom_fields = {}
	has_more = True
	offset = 0

	while has_more:
		resp = api.get('custom_fields/lead', params={ '_skip': offset, '_fields': 'id,name' })
		for field in resp['data']:
			current_custom_fields[field['name']] = field['id']
		offset += len(resp['data'])
		has_more = resp['has_more']

	### Create Custom Fields
	print "...Creating Any Missing Custom Fields"

	new_custom_fields = [
		{
    		"name": "Lead Source (Sample)",
    		"type": "text"
		},
		{
    		"name": "Industry (Sample)",
    		"type": "text"
		},
		{
			"name": "List Type (Sample)",
			"type": "text"
		}
	]

	custom_field_ids = []

	for custom_field in new_custom_fields:
		if custom_field['name'] in current_custom_fields:
			custom_field_ids.append("custom.{}".format(current_custom_fields[custom_field['name']]))
		else:
			try:
				create_custom_field = api.post('custom_fields/lead', data=custom_field)
				custom_field_ids.append("custom.{}".format(create_custom_field['id']))
				print "... {} Custom Field added".format(custom_field['name'])
			except:
				import_status = 'custom_field_error'
				return import_status
				break

	### Import Sample Leads
	print "... Creating Sample Leads"
	sample_lead_data = generate_lead_data(custom_field_ids=custom_field_ids, list_type=list_type)

	for lead in sample_lead_data:
		try:
			lead = api.post('lead', data=lead)
			print "... Importing {}".format(lead['name'])
		except:
			continue

	### Get Current Close.io Smart views
	print "...Getting Current Smart Views"
	current_smart_views = {}
	has_more = True
	offset = 0

	while has_more:
		resp = api.get('saved_search', params={ '_skip': offset, '_fields': 'id,name' })
		for query in resp['data']:
			current_smart_views[query['name']] = query['id']
		offset += len(resp['data'])
		has_more = resp['has_more']
		
	### Create Smart Views
	print "...Creating Any Missing Smart Views"
	smart_view_queries = [
		{
			'name': '[SAMPLE] {} Leads w/ Phone and Email'.format(list_type),
			'query': '"custom.Lead Source (Sample)":"Sample Lead Importer" "custom.List Type (Sample)":"{}" has:phone_numbers has:email_addresses sort:display_name'.format(list_type)
		},
		{
			'name': '[SAMPLE] {} Sample Leads'.format(list_type),
			'query': '"custom.Lead Source (Sample)":"Sample Lead Importer" "custom.List Type (Sample)":"{}" sort:display_name'.format(list_type)
		}
	]

	for query in smart_view_queries:
		if query['name'] not in current_smart_views:
			try:
				create_smart_view = api.post('saved_search', data=query)
				print "... {} Smart View added".format(query['name'])
			except:
				import_status = 'smartview_create_error'
				return import_status
				break

	import_status = 'https://app.close.io/search/%22custom.Lead%20Source%20(Sample)%22%3A%22Sample%20Lead%20Importer%22%20has%3Aphone_numbers%20has%3Aemail_addresses/'

	return import_status