Example #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', params={
            '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
Example #2
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
Example #3
0
                'assigned_to': from_user_id,
                '_order_by': 'date_created',
                '_skip': offset,
                '_fields': 'id'
            }

            if not args.all_tasks:
                payload['is_complete'] = False

            resp = api.get('task', data=payload)

            tasks = resp['data']
            for task in tasks:
                if args.confirmed:
                    try:
                        api.put('task/'+task['id'], data={'assigned_to': to_user_id})
                    except APIError as e:
                        tasks_errors += 1
                        if not args.continue_on_error:
                            raise e
                        logging.error('task %s skipped with error %s' % (task['id'], e))
                logging.info('updated %s' % task['id'])
                updated_tasks += 1

            offset += len(tasks)
            has_more = resp['has_more']

    # opportunities
    updated_opportunities = 0
    if args.opportunities or args.all_opportunities:
        has_more = True
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'
    print 'Status not found: {0}'.format(args.status)
    sys.exit(1)

new_status_id = new_status_id[0]

print 'Gathering opportunities for {0}'.format(args.query)

has_more = True
offset = 0
limit = 50
opp_ids = []

while has_more:
    resp = api.get('lead', data={'_skip': offset, '_limit': limit, 'query': args.query})
    opp_ids.extend([opp['id'] for lead in resp['data'] for opp in lead['opportunities']])
    has_more = resp['has_more']
    offset += limit

ans = raw_input('{0} opportunities found. Do you want to update all of them to {1}? (y/n): '.format(len(opp_ids), args.status))
if ans.lower() != 'y':
    sys.exit(0)

print 'Updating opportunities to {0}'.format(args.status)

# Update opps
for opp_id in opp_ids:
    resp = api.put('opportunity/{0}'.format(opp_id), data={'status_id': new_status_id})

print 'Done!'

Example #6
0
        tag_templates[r['tag'].lower()] = (r['custom_field_name'], r['custom_field_value'])

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

while has_more:
    resp = api.get('lead', data={
        'query': 'custom.Tags:* sort:created',
        '_skip': offset,
        '_fields': 'id,custom'
    })

    leads = resp['data']

    for l in leads:
        if 'Tags' in l['custom'].keys():
            tags = [t.strip() for t in l['custom']['Tags'].split(',')]
            new_fields = {}
            for t in tags:
                t_lower = t.lower()
                if t_lower in tag_templates.keys():
                    new_fields['custom.' + tag_templates[t_lower][0]] = tag_templates[t_lower][1]

            print l['id'], 'Tags:', l['custom']['Tags']
            print '...', new_fields
            api.put('lead/'+l['id'], data=new_fields)

    offset += max(0, len(leads) - 1)
    has_more = resp['has_more']
Example #7
0
            resp = api.get('task', params=payload)

            tasks = resp['data']
            for task in tasks:
                if args.confirmed:
                    full_tasks.append(task['id'])
                else:
                    logging.info(f'updated {task["id"]}')
                    updated_tasks += 1
            offset += len(tasks)
            has_more = resp['has_more']

        for task_id in full_tasks:
            try:
                api.put('task/' + task_id, data={'assigned_to': to_user_id})
                logging.info(f'updated {task_id}')
                updated_tasks += 1
            except APIError as e:
                tasks_errors += 1
                if not args.continue_on_error:
                    raise e
                logging.error(f'task {task["id"]} skipped with error {str(e)}')

    # opportunities
    updated_opportunities = 0
    if args.opportunities or args.all_opportunities:
        has_more = True
        offset = 0
        while has_more:
            payload = {
Example #8
0
              ISO_COUNTRIES[args.new_code]))

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

while has_more:
    resp = api.get('lead',
                   params={
                       'query': LEADS_QUERY,
                       '_skip': offset,
                       '_fields': 'id,addresses'
                   })

    leads = resp['data']

    for lead in leads:
        need_update = False
        for address in lead['addresses']:
            if address['country'] == args.old_code:
                address['country'] = args.new_code
                need_update = True
        if need_update:
            if args.confirmed:
                api.put('lead/' + lead['id'],
                        data={'addresses': lead['addresses']})
            logging.info('updated %s' % lead['id'])

    offset += len(leads)
    has_more = resp['has_more']
from closeio_api.utils import CsvReader

parser = argparse.ArgumentParser(description='Remove email addresses from contacts in CSV file')
parser.add_argument('--api-key', '-k', required=True, help='API Key')
parser.add_argument('--confirmed', action='store_true', help='Really run this?')
parser.add_argument('file', help='Path to the csv file')
args = parser.parse_args()

reader = CsvReader(args.file)

headers = dict([(name, idx,) for idx, name in enumerate(reader.next())]) # skip the 1st line header

if any(field not in headers for field in ['contact_id', 'email_address']):
    print 'contact_id or email_address headers could not be found in your csv file.'
    sys.exit(-1)

api = CloseIO_API(args.api_key, async=False)

for row in reader:
    contact_id = row[headers['contact_id']]
    email_address = row[headers['email_address']]
    try:
        contact = api.get('contact/' + contact_id) 
        if not contact['emails']:
            continue
        emails = filter(lambda email: email['email'] != email_address, contact['emails'])
        if args.confirmed:
            resp = api.put('contact/' + contact_id, {'emails': emails}) 
    except APIError:
        pass
Example #10
0
                    'direction': activity['direction'],
                    'duration': activity['duration'],
                    'voicemail_duration': activity['voicemail_duration'],
                    'note': activity['note'],
                    'source': activity['source'],
                    'status': activity['status'],
                    'remote_phone': activity['remote_phone'],
                    'phone': activity['phone'],
                    'local_phone': activity['local_phone'],
                    'recording_url': activity['recording_url'],
                    'date_created': activity['date_created'],
                    'date_updated': activity['date_updated']
                }

                if activity['user_id'] in target_user_ids:
                    new_call['user_id'] = activity['user_id']

                if activity['transferred_from'] in target_user_ids:
                    new_call['transferred_from'] = activity['transferred_from']

                if activity['transferred_to'] in target_user_ids:
                    new_call['transferred_to'] = activity['transferred_to']

                target_api.post('activity/call', data=new_call)
            logging.info(
                'target: %s added call: %s  duration: %s' %
                (new_lead['id'], activity['phone'], activity['duration']))
    if args.delete:
        api.put('lead/' + lead['id'])
        logging.info('deleted source lead %s' % (lead['id'], ))
Example #11
0
for row in reader:
    contact_id = row['contact_id']
    email_address = row['email_address']

    if args.verbose:
        print(f'Attempting to remove {email_address} from {contact_id}')

    try:
        contact = api.get('contact/' + contact_id)

        if not contact['emails']:
            if args.verbose:
                print(
                    f'Skipping {contact_id} because it has no email addresses')
            continue

        emails = list(
            filter(
                lambda email: email['email'] != email_address,
                contact['emails'],
            ))
        if args.confirmed:
            resp = api.put('contact/' + contact_id, {'emails': emails})
            if args.verbose:
                print(f'Removed {email_address} from {contact_id}')
    except APIError as e:
        if args.verbose:
            print(
                f'Encountered an API error ({e.response.status_code}): {e.response.text}'
            )
                choices_data[field_name].extend(field["choices"])

            if action == "create":
                print "Error: " + field_name + " already exists.  Choose another name or use update or replace."
                sys.exit(1)
            elif field["type"] != "choices":
                print "Error: " + field_name + " does not have a choices field type."
                sys.exit(1)

    if not field_id and action in ("update", "replace"):
        print "Error: " + field_name + " not found.  Remove --update if you wish to create a new field with this name."
        sys.exit(1)

        # Only runs against the org if --confirmed is used.
        # Uses post for creating and put for update/replace
    if args.confirmed:
        if action == "create":
            api.post(
                "custom_fields/lead", data={"name": field_name, "type": "choices", "choices": choices_data[field_name]}
            )
            print "Successfully created " + field_name + "!"
        else:
            api.put("custom_fields/lead/" + field_id, data={"choices": choices_data[field_name]})
            if action == "update":
                print "Successfully updated existing values for " + field_name + "!"
            else:
                print "Successfully replaced existing values for " + field_name + "!"
    else:
        print "No problems detected with " + field_name + "!"
        print "Use --confirmed if you wish to run these changes against your Close.io org."
Example #13
0
            resp = api.get(
                "lead",
                params={
                    "query": 'company:"%s" sort:created' % r["company"],
                    "_fields": "id,display_name,name,contacts,custom",
                    "limit": 1,
                },
            )
            logging.debug("received: %s" % resp)
            if resp["total_results"]:
                lead = resp["data"][0]

        if lead:
            logging.debug("to sent: %s" % payload)
            if args.confirmed:
                api.put("lead/" + lead["id"], data=payload)
            logging.info(
                "line %d updated: %s %s" % (c.line_num, lead["id"], lead.get("name") if lead.get("name") else "")
            )
            updated_leads += 1
        # new lead
        elif lead is None and not args.disable_create:
            logging.debug("to sent: %s" % payload)
            if args.confirmed:
                lead = api.post("lead", data=payload)
            logging.info("line %d new: %s %s" % (c.line_num, lead["id"] if args.confirmed else "X", payload["name"]))
            new_leads += 1

        notes = [r[x] for x in r.keys() if re.match(r"note[0-9]", x) and r[x]]
        for note in notes:
            if args.confirmed:
            lead = resp
        else:
            # first lead in the company
            resp = api.get('lead', data={
                'query': 'company:"%s" sort:created' % r['company'],
                '_fields': 'id,display_name,name,contacts,custom',
                'limit': 1
            })
            logging.debug('received: %s' % resp)
            if resp['total_results']:
                lead = resp['data'][0]

        if lead:
            logging.debug('to sent: %s' % payload)
            if args.confirmed:
                api.put('lead/' + lead['id'], data=payload)
            logging.info('line %d updated: %s %s' % (c.line_num,
                                                     lead['id'],
                                                     lead.get('name') if lead.get('name') else ''))
            updated_leads += 1
        # new lead
        elif lead is None and not args.disable_create:
            logging.debug('to sent: %s' % payload)
            if args.confirmed:
                lead = api.post('lead', data=payload)
            logging.info('line %d new: %s %s' % (c.line_num,
                                                 lead['id'] if args.confirmed else 'X',
                                                 payload['name']))
            new_leads += 1

        notes = [r[x] for x in r.keys() if re.match(r'note[0-9]', x) and r[x]]
parser.add_argument('--development', action='store_true', help='Use a development server rather than production.')
args = parser.parse_args()

api = CloseIO_API(args.api_key, development=args.development)

skip = 0
has_more = True

while has_more:
    resp = api.get('lead', data={'_skip': skip})
    leads = resp['data']

    for lead in leads:
        n_fields_deleted = 0
        custom = lead['custom'].copy()

        for field in DELETE_FIELDS:
            if custom.get(field):
                del custom[field]
                n_fields_deleted += 1

        if n_fields_deleted:
            print "LEAD: %s" % lead['id']
            print "\tBEFORE", lead['custom']
            print "\tAFTER", custom
            print
            api.put('lead/' + lead['id'], data={'custom': custom})

    skip += len(leads)
    has_more = resp['has_more']
                               'query':
                               'company:"%s" sort:created' %
                               r['company'].decode('utf-8'),
                               '_fields':
                               'id,display_name,name,contacts,custom',
                               'limit':
                               1
                           })
            logging.debug('received: %s' % resp)
            if resp['total_results']:
                lead = resp['data'][0]

        if lead:
            logging.debug('to sent: %s' % payload)
            if args.confirmed:
                api.put('lead/' + lead['id'], data=payload)
            logging.info('line %d updated: %s %s' %
                         (c.line_num, lead['id'],
                          lead.get('name') if lead.get('name') else ''))
            updated_leads += 1
        # new lead
        elif lead is None and not args.disable_create:
            logging.debug('to sent: %s' % payload)
            if args.confirmed:
                lead = api.post('lead', data=payload)
            logging.info('line %d new: %s %s' %
                         (c.line_num, lead['id'] if args.confirmed else 'X',
                          payload['name'].decode('utf-8')))
            new_leads += 1

        notes = [r[x] for x in r.keys() if re.match(r'note[0-9]', x) and r[x]]
Example #17
0
offset = 0
limit = 50
opp_ids = []

while has_more:
    resp = api.get('lead',
                   data={
                       '_skip': offset,
                       '_limit': limit,
                       'query': args.query
                   })
    opp_ids.extend(
        [opp['id'] for lead in resp['data'] for opp in lead['opportunities']])
    has_more = resp['has_more']
    offset += limit

ans = raw_input(
    '{0} opportunities found. Do you want to update all of them to {1}? (y/n): '
    .format(len(opp_ids), args.status))
if ans.lower() != 'y':
    sys.exit(0)

print 'Updating opportunities to {0}'.format(args.status)

# Update opps
for opp_id in opp_ids:
    resp = api.put('opportunity/{0}'.format(opp_id),
                   data={'status_id': new_status_id})

print 'Done!'
Example #18
0
                    help='Use a development server rather than production.')
args = parser.parse_args()

api = CloseIO_API(args.api_key, development=args.development)

skip = 0
has_more = True

while has_more:
    resp = api.get('lead', data={'_skip': skip})
    leads = resp['data']

    for lead in leads:
        n_fields_deleted = 0
        custom = lead['custom'].copy()

        for field in DELETE_FIELDS:
            if custom.get(field):
                del custom[field]
                n_fields_deleted += 1

        if n_fields_deleted:
            print "LEAD: %s" % lead['id']
            print "\tBEFORE", lead['custom']
            print "\tAFTER", custom
            print
            api.put('lead/' + lead['id'], data={'custom': custom})

    skip += len(leads)
    has_more = resp['has_more']
logging.info('old country: %s (%s) -> new country: %s (%s) ' % (args.old_code, ISO_COUNTRIES[args.old_code],
                                                                args.new_code, ISO_COUNTRIES[args.new_code]))

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

while has_more:
    resp = api.get('lead', data={
        'query': LEADS_QUERY,
        '_skip': offset,
        '_fields': 'id,addresses'
    })

    leads = resp['data']

    for lead in leads:
        need_update = False
        for address in lead['addresses']:
            if address['country'] == args.old_code:
                address['country'] = args.new_code
                need_update = True
        if need_update:
            if args.confirmed:
                api.put('lead/'+lead['id'], data={'addresses': lead['addresses']})
            logging.info('updated %s' % lead['id'])

    offset += len(leads)
    has_more = resp['has_more']
Example #20
0
                'sequence_id': sequence['id']
            },
        )
        from_subs += [
            i for i in sub_results['data']
            if i['sender_email'] == args.from_email
            and i['status'] in ['active', 'paused', 'error', 'goal']
        ]
        offset += len(sub_results['data'])
        has_more = sub_results['has_more']
        print(offset)

print(f"Total subscriptions: {len(from_subs)}")
print("Updating subscriptions")

count = 0
for sub in from_subs:
    try:
        api.put(
            f"sequence_subscription/{sub['id']}",
            data={
                'sender_name': args.sender_name,
                'sender_account_id': args.sender_account_id,
                'sender_email': args.to_email,
            },
        )
        count += 1
        print(f"{count}: {sub['id']}")
    except APIError as e:
        print(f"Can't update sequence {sub['id']} because {str(e)}")
Example #21
0
parser.add_argument('--to-email', '-t', required=True, help='Email address you want to use to send sequence')
parser.add_argument('--sender-account-id', '-s', required=True, help='Email account id you want to use to send sequence')
parser.add_argument('--sender-name', '-n', required=True, help='Sender name you want to use to send sequence')

args = parser.parse_args()
api = CloseIO_API(args.api_key)

has_more = True
offset = 0
from_subs = []
count = 0

print "Getting sequence subscriptions"

while has_more:
	sub_results = api.get('sequence_subscription', params={ '_skip': offset, 'fields': 'id,sender_email,sender_name,sender_account_id,status' })
	from_subs += [i for i in sub_results['data'] if i['sender_email'] == args.from_email and i['status'] in ['active', 'paused']]
	offset += len(sub_results['data'])
	print offset
	has_more = sub_results['has_more']

print "Total subscriptions: %s" % len(from_subs)
print "Updating subscriptions"

for sub in from_subs:
	try:
		api.put('sequence_subscription/' + sub['id'], data={ 'sender_name': args.sender_name, 'sender_account_id': args.sender_account_id, 'sender_email': args.to_email })
		count += 1
		print "%s: %s" % (count, sub['id'])
	except APIError as e:
		print "Can't update sequence %s because %s" % (sub['id'], str(e))