def update_fulcrum(*, record, task, api_key, form_id): """Summary Args: record (TYPE): Description task (TYPE): Description api_key (TYPE): Description form_id (TYPE): Description Returns: TYPE: Description Raises: Exception: Description """ record = map_fields(record, KNACK_FULC_FIELDMAP, method="knack_to_fulcrum") payload = fulcutil.get_template() payload = fulcutil.format_record(record, payload, form_id) fulcrum = Fulcrum(key=api_key) if task == "create": res = fulcrum.records.create(payload) elif task == "update": res = fulcrum.records.update(form_id, payload) else: raise Exception(f"Uknown update task: {task}") return res
def initialize_app(self, argv): commands = [List, Get, Remove, ListRemoved] for command in commands: self.command_manager.add_command(command.__name__.lower(), command) #def __init__(self, db, client, storage_cfg): opts = self.options client = Fulcrum(key=opts.apikey[0]) self.api_manager = ApiManager(opts.dburl[0], client, { 'root_dir': opts.storage[0], 'url_base': opts.urlbase[0] })
for row in tbl: csvfile.write("\"" + row[0] + "\",\"" + str(row[1])) csvfile.write("\"\n") csvfile.write("\"\n") csvfile.close() if __name__ == '__main__': full_path = sys.argv[0] api_key = os.environ['FULCRUM_API_KEY'] fulcrum = Fulcrum(key=api_key) headers = { 'Accept': 'application/json', 'Content-Type': 'application/json; charset=UTF-8', 'X-ApiToken': api_key } street_times = [] filtered_street_times = [] new_project = {} wrapper = {} count = 0 allotted_time_per_street = 60 form_name = 'CH Voters 2017'
import json import FulcrumApplicationToSalesforceObject as fts from fulcrum import Fulcrum _sfdcPrefix = 'f_' _sfdcUsername = "******" _sfdcPassword = "******" _sfdcToken = "yourSalesforceSecurityToken" _sfdcSandbox = True _fulcrumXApiToken = "yourFulcrumAPIToken" #The specific Fulcrum Application Form you would like to create in salesforce _fulcrumFormId = "yourFulcumApplicationID" fulcrum = Fulcrum(key=_fulcrumXApiToken) fulcrumToSalesforce = fts.FulcrumApplicationToSalesforceObject() # Get Individual Fulcrum Form Fulcrum Applications fulcrumForm = fulcrum.form.find(_fulcrumFormId) # Create Salesforce Object From Fulcrum Form fulcrumToSalesforce.construct_fulcrum_sfdc_object(fulcrumForm, 'create')
from fulcrum import Fulcrum import os import sys import requests from pprint import pprint as pp requests.packages.urllib3.disable_warnings() #Ask user for API key, then create Fulcrum access object #fulcrumKey = raw_input('Enter the Fulcrum API key: ') fulcrumKey = '' fulcrum = Fulcrum(key=fulcrumKey) form = fulcrum.forms.find('') records = fulcrum.records.search(url_params={'form_id': ''}) class Form(object): def __init__(self, data):
if ('child_classifications' not in level): return else: count = count + 1 for l in level['child_classifications']: recursive(l, count) parser = argparse.ArgumentParser( description= 'This program takes a classification set from the API and turns it into a csv file.' ) parser.add_argument('-t', '--token', help='API token', required=True) parser.add_argument('-cs', '--classSetId', help='ID of classification set', required=True) args = vars(parser.parse_args()) token = args['token'] # fulcrum API token classId = args['classSetId'] # classification set id fulcrum = Fulcrum(key=token) classSet = fulcrum.classification_sets.find(classId) count = 0 #jsonData = json.loads(classSet) items = classSet['classification_set']['items'] file = csv.writer(open("export.csv", "w+")) for item in items: recursive(item, count)
class FulcrumRecordToSalesforceRecord: _sfdcSession_id, _sfdcInstance = SalesforceLogin(username=_sfdcUsername, password=_sfdcPassword, security_token=_sfdcToken, domain=_sfdcDomain) sfdc = Salesforce(instance=_sfdcInstance, session_id=_sfdcSession_id) fulcrum = Fulcrum(key=_fulcrumXApiToken) fulcrumHeaders = {'X-ApiToken': _fulcrumXApiToken} def sf_api_call(self, action, parameters={}, method='get', data={}, multipart=False, boundary=None): """ Helper function to make calls to Salesforce REST API. Parameters: action (the URL), URL params, method (get, post or patch), data for POST/PATCH. """ headers = {} if multipart == False: headers = { 'Content-type': 'application/json', 'Accept-Encoding': 'gzip', 'Authorization': 'OAuth ' + self._sfdcSession_id, } else: headers = { 'Content-type': 'multipart/form-data; boundary=' + boundary, 'Accept-Encoding': 'gzip', 'Authorization': 'OAuth ' + self._sfdcSession_id, } if method == 'get': r = requests.request(method, 'https://' + self._sfdcInstance + action, headers=headers, params=parameters, timeout=30) elif method in ['post', 'patch']: r = requests.request(method, 'https://' + self._sfdcInstance + action, headers=headers, json=data, params=parameters, timeout=10) else: # other methods not implemented in this example raise ValueError('Method should be get or post or patch.') #print('Debug: API %s call: %s' % (method, r.url) ) if r.status_code < 300: if method == 'patch': return None else: return r.json() else: raise Exception('API error when calling %s : %s' % (r.url, r.content)) # Generates a random string def id_generator(self, size=32, chars=string.ascii_uppercase + string.digits): return ''.join(random.choice(chars) for _ in range(size)) #checks to see if a key exists in a dictonary def checkKey(self, dictionary, key): try: if key in dictionary.keys(): return True else: return False except KeyError: return False ## pass JSON Directly def composite_salesforce_create(self, objectId, records): response = self.sfdc.restful(method='POST', path='composite/tree/' + objectId, json=records) return response #must have Salesforce record IDs def composite_salesforce_update(self, objectId, extCustomField, extIdValue, records): response = self.sfdc.restful(method='PATCH', path='composite/sobjects', json=records) return response def composite_salesforce_request(self, objectId, extCustomField, extIdValue, records): response = self.sfdc.restful(method='POST', path='composite/sobjects/' + objectId, json=records) return reponse # Data should either be a single JSON encapsulating base64 encoded blob up to 34MB # Or a multipart message encapsulating a base64 encoded blob up to 2GB # https://developer.salesforce.com/docs/atlas.en-us.api_rest.meta/api_rest/dome_sobject_insert_update_blob.htm def contentVersion_salesforce_create(self, data): return self.sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data=data) def contentVersion_2GB_salesforce_create(self, data, boundary): return self.sf_api_call('/services/data/v40.0/sobjects/ContentVersion', method="post", data=data, multipart=True, boundary=boundary) # Data should be an ID def contentVersion_salesforce_get(self, data): return self.sf_api_call( '/services/data/v40.0/sobjects/ContentVersion/%s' % data) def contentDocumentLink_salesforce_create(self, data): return self.sf_api_call( '/services/data/v40.0/sobjects/ContentDocumentLink', method='post', data=data) def create_output_json(self, recordJson): recordJson = json.dumps(recordJson) recordJson = recordJson[1:-1] recordJson = recordJson.replace('null', '') return recordJson def process_generate_field(self, fieldId, fieldValue, fieldType='Data'): print ' ' + str(fieldType) + ': ' + str(_sfdcPrefix) + str( fieldId) + '__c:' + str(fieldValue) if fieldType == 'Latitude' or fieldType == 'Longitude': return { _sfdcPrefix + fieldId + '__' + fieldType + '__s': fieldValue } else: return {_sfdcPrefix + fieldId + '__c': fieldValue} def upload_2GB_file_to_salesforce_and_attach_to_record( self, recordId, fileTitle, fileDescription, fileName, fileContents): boundary = self.id_generator() fileContents = base64.b64encode(fileContents) #Multi part request can handle 2GB Max ContentVersionMetadata = { 'Title': fileTitle, 'Description': fileDescription, 'PathOnClient': fileName, } ContentVersionData = """--""" + boundary + """ Content-Disposition: form-data; name="entity_content"; Content-Type: application/json { "Title" : """ + '"' + fileTitle + '"' + """, "Description" : """ + '"' + fileDescription + '"' + """, "PathOnClient" : """ + '"' + fileName + '"' + """ } --""" + boundary + """ Content-Disposition: form-data; name="VersionData"; filename=""" + '"' + fileName + '"' + """ Content-Type: application/octet-stream """ + fileContents + """ --""" + boundary + """--""" # 1: Insert the Content Document ContentVersion = self.contentVersion_2GB_salesforce_create( data=ContentVersionData, boundary=boundary) ContentVersionId = ContentVersion.get('id') # 2: Get the ContentDocumentId from the just inserted ContentVersion ContentVersion = self.contentVersion_salesforce_get(ContentVersionId) ContentDocumentId = ContentVersion.get('ContentDocumentId') # 3: Create a ContentDocumentLink between the ContentDocumentId and the Record contentDocumentLinkMetadata = { 'ContentDocumentId': ContentDocumentId, 'LinkedEntityId': recordId, 'ShareType': 'V' } ContentDocumentLink = self.contentDocumentLink_salesforce_create( contentDocumentLinkMetadata) return { 'ContentVersionId': ContentVersionId, 'ContentDocumentId': ContentDocumentId, 'ContentDocumentLink': ContentDocumentLink } def upload_file_to_salesforce_and_attach_to_record(self, recordId, fileTitle, fileDescription, fileName, fileContent, fulcrumId): fileContent = base64.b64encode(fileContent) #Single part request can handle ~34MB Max ContentVersionData = { 'Title': fileTitle, 'Description': fileDescription, 'PathOnClient': fileName, 'VersionData': fileContent, _sfdcPrefix + 'Fulcrum_Id__c': fulcrumId, # _sfdcPrefix + 'Location__c':fulcrumLocation } # 1: Insert the Content Document ContentVersion = self.contentVersion_salesforce_create( data=ContentVersionData) ContentVersionId = ContentVersion.get('id') # 2: Get the ContentDocumentId from the just inserted ContentVersion ContentVersion = self.contentVersion_salesforce_get(ContentVersionId) ContentDocumentId = ContentVersion.get('ContentDocumentId') # 3: Create a ContentDocumentLink between the ContentDocumentId and the Record contentDocumentLinkMetadata = { 'ContentDocumentId': ContentDocumentId, 'LinkedEntityId': recordId, 'ShareType': 'V' } ContentDocumentLink = self.contentDocumentLink_salesforce_create( contentDocumentLinkMetadata) return { 'ContentVersionId': ContentVersionId, 'ContentDocumentId': ContentDocumentId, 'ContentDocumentLink': ContentDocumentLink } def process_file_fields(self, record, recordId): #print record newFiles = [] for fieldId in record['form_values']: files = self.detect_file_field_type_and_process_field( fieldId, record, recordId=recordId) #print files if isinstance(files, dict): newFiles.append(files) return newFiles def process_video_field(self, fieldValue, recordId): print 'Downloading Video File From Fulcrum ... ' + fieldValue[ 'video_id'] baseurl = _fulcrumBaseURL + 'videos/' + fieldValue['video_id'] blob = requests.request('GET', baseurl + '.mp4', headers=self.fulcrumHeaders) if blob.status_code == 200: videoMetadata = self.fulcrum.videos.find(fieldValue['video_id']) print 'Uploading Video File To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['video_id'] + ' Video', fileDescription=fieldValue['caption'], fileName=fieldValue['video_id'] + '.mp4', fileContent=blob.content, fulcrumId=fieldValue['video_id']) blob = requests.request('GET', baseurl + '/track.json', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Video Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['video_id'] + ' JSON Track', fileDescription='JSON Track Of\n' + fieldValue['caption'], fileName=fieldValue['video_id'] + '-track.json', fileContent=blob.content) blob = requests.request('GET', baseurl + '/track.geojson', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Video GeoJSON Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['video_id'] + ' GEO JSON Track', fileDescription='GeoJSON Track Of\n' + fieldValue['caption'], fileName=fieldValue['video_id'] + '-track.geojson', fileContent=blob.content) blob = requests.request('GET', baseurl + '/track.gpx', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Video GPX Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['video_id'] + ' GPX Track', fileDescription='GPX Track Track Of\n' + fieldValue['caption'], fileName=fieldValue['video_id'] + '-track.gpx', fileContent=blob.content) blob = requests.request('GET', baseurl + '/track.kml', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Video KML Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['video_id'] + ' KML Track', fileDescription='KML Track Track Of\n' + fieldValue['caption'], fileName=fieldValue['video_id'] + '-track.kml', fileContent=blob.content) return def process_photo_field(self, fieldValue, recordId): print 'Downloading Photo File From Fulcrum ... ' + fieldValue[ 'photo_id'] blob = requests.request('GET', _fulcrumBaseURL + 'photos/' + fieldValue['photo_id'] + '.jpg', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Photo File To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['photo_id'] + ' Photo', fileDescription=fieldValue['caption'], fileName=fieldValue['photo_id'] + '.jpg', fileContent=blob.content, fulcrumId=fieldValue['photo_id']) return def process_signature_field(self, fieldValue, recordId): print 'Downloading Signature File From Fulcrum ... ' + fieldValue[ 'signature_id'] blob = requests.request('GET', _fulcrumBaseURL + 'signature/' + fieldValue['signature_id'] + '.png', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Signature File To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['photo_id'] + ' Signature', fileDescription='Signed At: ' + fieldValue['timestamp'], fileName=fieldValue['signature_id'] + '.png', fileContent=blob.content, fulcrumId=fieldValue['signature_id']) return def process_audio_field(self, fieldValue, recordId): print 'Downloading Audio File From Fulcrum ... ' + fieldValue[ 'audio_id'] blob = requests.request('GET', _fulcrumBaseURL + 'audio/' + fieldValue['audio_id'] + '.mp4', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Audio File To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['audio_id'] + ' Video', fileDescription=fieldValue['caption'], fileName=fieldValue['audio_id'] + '.mp4', fileContent=blob.content, fulcrumId=fieldValue['audio_id']) blob = requests.request('GET', _fulcrumBaseURL + 'audio/' + fieldValue['audio_id'] + '/track.json', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Audio Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['audio_id'] + ' JSON Track', fileDescription='JSON Track Of\n' + fieldValue['caption'], fileName=fieldValue['audio_id'] + '-track.json', fileContent=blob.content) blob = requests.request('GET', _fulcrumBaseURL + 'audio/' + fieldValue['audio_id'] + '/track.geojson', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Audio GeoJSON Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['audio_id'] + ' GEO JSON Track', fileDescription='GeoJSON Track Of\n' + fieldValue['caption'], fileName=fieldValue['audio_id'] + '-track.geojson', fileContent=blob.content) blob = requests.request('GET', _fulcrumBaseURL + 'audio/' + fieldValue['audio_id'] + '/track.gpx', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Audio GPX Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['audio_id'] + ' GPX Track', fileDescription='GPX Track Track Of\n' + fieldValue['caption'], fileName=fieldValue['audio_id'] + '-track.gpx', fileContent=blob.content) blob = requests.request('GET', _fulcrumBaseURL + 'audio/' + fieldValue['audio_id'] + '/track.kml', headers=self.fulcrumHeaders) if blob.status_code == 200: print 'Uploading Audio KML Track To Salesforce... ' + recordId self.upload_file_to_salesforce_and_attach_to_record( recordId=recordId, fileTitle=fieldValue['audio_id'] + ' KML Track', fileDescription='KML Track Track Of\n' + fieldValue['caption'], fileName=fieldValue['audio_id'] + '-track.kml', fileContent=blob.content) return def process_date_field(self, fieldId, fieldValue): #Generate Date Time return self.process_generate_field(fieldId, fieldValue, 'Date') def process_datetime_field(self, record, isDateField, fieldId, fieldValue): #Generate Date Time # Check to see if the last field processed was a Date Field if isDateField != _isDateFieldDefault: dateValue = record['form_values'][isDateField] dateTimeValue = dateValue + ' ' + fieldValue return self.process_generate_field(isDateField + '_' + fieldId, dateTimeValue, 'DateTime') #Not paired with a Date Field else: return self.process_generate_field(fieldId, fieldValue, 'Time') def process_address_and_choice_field(self, fieldId, subFieldKey, subFieldValue): if subFieldValue == 'sub_thoroughfare': return self.process_generate_field(fieldId + '_1', subFieldValue, 'Street Number') elif subFieldKey == 'thoroughfare': return self.process_generate_field(fieldId + '_2', subFieldValue, 'Street Name') elif subFieldKey == 'suite': return self.process_generate_field(fieldId + '_3', subFieldValue, 'Suite') elif subFieldKey == 'locality': return self.process_generate_field(fieldId + '_4', subFieldValue, 'City') elif subFieldKey == 'sub_admin_area': return self.process_generate_field(fieldId + '_5', subFieldValue, 'County') elif subFieldKey == 'admin_area': return self.process_generate_field(fieldId + '_6', subFieldValue, 'State/Province') elif subFieldKey == 'postal_code': return self.process_generate_field(fieldId + '_7', subFieldValue, 'Postal Code') elif subFieldKey == 'country': return self.process_generate_field(fieldId + '_8', subFieldValue, 'Country') elif subFieldKey == 'choice_values': choices = [] multiSelectChoices = subFieldValue[0] for choice in subFieldValue: choices.append(choice) if multiSelectChoices != choice: multiSelectChoices += ';' + choice if len(choices) == 1: self.process_generate_field(fieldId, choices, 'Choices') else: return self.process_generate_field(fieldId, multiSelectChoices, 'Multiselect Choices') elif subFieldKey == 'other_values': for choice in subFieldValue: return self.process_generate_field(fieldId, choice, 'Other Choice') # Determine the type of field and process it. This handles files. def detect_file_field_type_and_process_field(self, fieldId, record, recordId, detail=False): fieldValue = '' if detail == False: fieldValue = record['form_values'][fieldId] elif detail == True: fieldValue = record[fieldId] isDictField = isinstance(fieldValue, dict) isListField = isinstance(fieldValue, list) #print fieldValue if isListField == True: for complexFieldValue in fieldValue: #print complexFieldValue isComplexDictField = isinstance(complexFieldValue, dict) if isComplexDictField == True: isRepeatingSections = self.checkKey( complexFieldValue, 'form_values') isPhotoField = self.checkKey(complexFieldValue, 'photo_id') isVideoField = self.checkKey(complexFieldValue, 'video_id') isAudioField = self.checkKey(complexFieldValue, 'audio_id') if isPhotoField == True: print "Photo Field Detected..." return self.process_photo_field( complexFieldValue, recordId) elif isVideoField == True: print "Video Field Detected..." return self.process_video_field( complexFieldValue, recordId) elif isAudioField == True: print "Audio Field Detected..." return self.process_audio_field( complexFieldValue, recordId) elif isRepeatingSections == True: print "Child Record Detected..." return self.process_file_fields( complexFieldValue, recordId) elif isDictField == True: isSignatureField = self.checkKey(fieldValue, 'signature_id') if isSignatureField == True: print "Signature Field Detected..." return self.process_signature_field(fieldValue, recordId) # Determine the type of field and process it. This handles data. def detect_field_type_and_process_field(self, fieldId, record, isDateField=_isDateFieldDefault, detail=False): fieldValue = '' if detail == False: fieldValue = record['form_values'][fieldId] elif detail == True: fieldValue = record[fieldId] isListField = isinstance(fieldValue, list) isDictField = isinstance(fieldValue, dict) if isListField == True: for complexFieldValue in fieldValue: isRepeatingSections = self.checkKey(complexFieldValue, 'form_values') isDictComplexField = isinstance(complexFieldValue, dict) isJunctionObject = self.checkKey(complexFieldValue, 'record_id') elif isDictField == True: for subFieldKey in fieldValue: subFieldValue = fieldValue[subFieldKey] return self.process_address_and_choice_field( fieldId, subFieldKey, subFieldValue) # Date Time field elif re.match(r"([0-2][0-9]:[0-5][0-9])", fieldValue): return self.process_datetime_field(record, isDateField, fieldId, fieldValue) # Date field elif re.match(r"([1-2][0-9][0-9][0-9]-[0-1][0-9]-[0-3][0-9])", fieldValue): #Mark that this loop was a Date, in prep for a Time Field isDateField = fieldId return self.process_date_field(fieldId, fieldValue) #easy field else: return self.process_generate_field(fieldId, fieldValue) def generate_junction_records(self, complexFormValues): return def generate_detail_fields(self, complexFormValues): dict(complexFormValues) sfdcFields = [] for detailRecord in complexFormValues: isDateField = _isDateFieldDefault fieldAppend = self.detect_field_type_and_process_field( detailRecord, complexFormValues, isDateField, True) #print fieldAppend if isinstance(fieldAppend, dict): sfdcFields.append(fieldAppend) if isDateField != detailRecord: isDateField = _isDateFieldDefault sfdcFields = json.dumps(sfdcFields).replace('[', '').replace( ']', '').replace('{', '').replace('}', '') return sfdcFields def generate_fields(self, record): sfdcFields = [] isDateField = _isDateFieldDefault #print record for fieldId in record['form_values']: fieldAppend = self.detect_field_type_and_process_field( fieldId, record, isDateField) #print fieldAppend if isinstance(fieldAppend, dict): sfdcFields.append(fieldAppend) # If this Loop was not a Date Field, Reset Back to Default Value if isDateField != fieldId: isDateField = _isDateFieldDefault sfdcFields = json.dumps(sfdcFields).replace('[', '').replace( ']', '').replace('{', '').replace('}', '') return sfdcFields def create_sfdc_fulcrum_record(self, record): objectId = (_sfdcPrefix + record['form_id'] + '__c').replace('-', '_') sfdcCreateRecords = self.generate_sfdc_fulcrum_record(record) sfdcCreateRecords = json.loads(sfdcCreateRecords) return fulcrumToSalesforce.composite_salesforce_create( objectId, sfdcCreateRecords) def update_sfdc_fulcrum_record(self, record): objectId = (_sfdcPrefix + record['form_id'] + '__c').replace('-', '_') sfdcObject = SFType(objectId, self.sfdc.session_id, self.sfdc.sf_instance) recordExists = sfdcObject.get_by_custom_id( _sfdcPrefix + 'fulcrum_id__c', record['id']) if recordExists: ## Get Child Records for fieldId in record['form_values']: fieldValue = record['form_values'][fieldId] isListField = isinstance(fieldValue, list) if isListField == True: complexFieldType = fieldValue[0] isRepeatingSections = self.checkKey( complexFieldType, 'form_values') isJunctioonObject = self.checkKey(complexFieldType, 'record_id') if isRepeatingSections == True: objectId = _sfdcPrefix + record['form_id'][ 0:13].replace('-', '_') + '_' + fieldId + '_d__c' objectReferenceId = _sfdcPrefix + record['form_id'][ 0:13].replace('-', '_') + '_' + fieldId + '_d__r' sfdcInsertRecord = '' for complexFieldValue in fieldValue: detailRecordExists = sfdcObject.get_by_custom_id( _sfdcPrefix + 'fulcrum_id__c', complexFieldValue['id']) if detailRecordExists: sfdcRecordUpdate = generate_sfdc_fulcrum_detail_record( self, complexFieldValue) print sfdcRecordUpdate exit() else: self.create_sfdc_fulcrum_record(record) def generate_sfdc_fulcrum_record(self, record): print '---------------------------------------' print 'Processing Fulcrum Record...' objectId = (_sfdcPrefix + record['form_id'] + '__c').replace('-', '_') sfdcRecord = self.standard_fields_master_record(record) sfdcFields = self.generate_fields(record) objectIdString = '"' + objectId + '"' recordIdString = '"' + record['id'] + '"' sfdcRecord = json.dumps(sfdcRecord).replace('[', '').replace( ']', '').replace('{', '').replace('}', '') sfdcDetailRecords = self.generate_sfdc_fulcrum_detail_records(record) if sfdcDetailRecords is None: sfdcRecord = """{"records": [{"attributes": {"type" : """ + objectIdString + """, "referenceId": """ + recordIdString + """ }, """ + sfdcRecord + ',' + sfdcFields + """ }]}""" else: detailRecordJson = sfdcDetailRecords[0] for detailRecord in sfdcDetailRecords: if detailRecord != detailRecordJson: detailRecordJson += "," + detailRecordJson sfdcRecord = """{"records": [{"attributes": {"type" : """ + objectIdString + """, "referenceId": """ + recordIdString + """ }, """ + sfdcRecord + ',' + sfdcFields + ', ' + detailRecordJson + """ }]}""" return sfdcRecord def generate_sfdc_fulcrum_detail_record(self, complexFieldValue): complexFormValues = complexFieldValue['form_values'] sfdcFields = self.generate_detail_fields(complexFormValues) objectIdString = '"' + objectId + '"' recordIdString = '"' + complexFieldValue['id'] + '"' #sfdcRecord = json.dumps (sfdcRecord).replace('[','').replace(']','').replace('{','').replace('}','') sfdcRecord = json.dumps(sfdcRecord).replace('[', '').replace( ']', '').replace('{', '').replace('}', '') sfdcRecord = """, { "attributes": {"type" : """ + objectIdString + """ , "referenceId": """ + recordIdString + """ }, """ + sfdcRecord + ',' + sfdcFields + """ }""" sfdcInsertRecord += sfdcRecord def standard_fields_master_record(self, record): sfdcRecord = [] if record['status'] is not None: sfdcRecord.append( self.process_generate_field('status', record['status'], 'Status')) if record['version'] is not None: sfdcRecord.append( self.process_generate_field('version', record['version'], 'Version')) if record['id'] is not None: sfdcRecord.append( self.process_generate_field('fulcrum_id', record['id'], 'Id')) if record['created_at'] is not None: sfdcRecord.append( self.process_generate_field('created_at', record['created_at'], 'Created At')) if record['updated_at'] is not None: sfdcRecord.append( self.process_generate_field('updated_at', record['updated_at'], 'Updated At')) if record['client_created_at'] is not None: sfdcRecord.append( self.process_generate_field('client_created_at', record['client_created_at'], 'Client Created At')) if record['client_updated_at'] is not None: sfdcRecord.append( self.process_generate_field('client_updated_at', record['client_updated_at'], 'Client Updated At')) if record['created_by'] is not None: sfdcRecord.append( self.process_generate_field('created_by', record['created_by'], 'Created By')) if record['created_by_id'] is not None: sfdcRecord.append( self.process_generate_field('created_by_id', record['created_by_id'], 'Created By Id')) if record['updated_by'] is not None: sfdcRecord.append( self.process_generate_field('updated_by', record['updated_by'], 'Updated By')) if record['updated_by_id'] is not None: sfdcRecord.append( self.process_generate_field('updated_by_id', record['updated_by_id'], 'Updated By Id')) if record['created_location'] is not None: sfdcRecord.append( self.process_generate_field('created_location', record['created_location'], 'Created Location')) if record['updated_location'] is not None: sfdcRecord.append( self.process_generate_field('updated_location', record['updated_location'], 'Updated Location')) if record['created_duration'] is not None: sfdcRecord.append( self.process_generate_field('created_duration', record['created_duration'], 'Created Duration')) if record['updated_duration'] is not None: sfdcRecord.append( self.process_generate_field('updated_duration', record['updated_duration'], 'Updated Duration')) if record['edited_duration'] is not None: sfdcRecord.append( self.process_generate_field('edited_duration', record['edited_duration'], 'Edited Duration')) if record['project_id'] is not None: sfdcRecord.append( self.process_generate_field('project_id', record['project_id'], 'Project Id')) if record['changeset_id'] is not None: sfdcRecord.append( self.process_generate_field('changeset_id', record['changeset_id'], 'Change Set ID')) if record['assigned_to'] is not None: sfdcRecord.append( self.process_generate_field('assigned_to', record['assigned_to'], 'Assigned To')) if record['assigned_to_id'] is not None: sfdcRecord.append( self.process_generate_field('assigned_to_id', record['assigned_to_id'], 'Assigned To Id')) if record['form_id'] is not None: sfdcRecord.append( self.process_generate_field('form_id', record['form_id'], 'Form Id')) if record['latitude'] is not None: sfdcRecord.append( self.process_generate_field('location', record['latitude'], 'Latitude')) if record['longitude'] is not None: sfdcRecord.append( self.process_generate_field('location', record['longitude'], 'Longitude')) if record['speed'] is not None: sfdcRecord.append( self.process_generate_field('speed', record['speed'], 'Speed')) if record['course'] is not None: sfdcRecord.append( self.process_generate_field('course', record['course'], 'Course')) if record['horizontal_accuracy'] is not None: sfdcRecord.append( self.process_generate_field('horizontal_accuracy', record['horizontal_accuracy'], 'Horizontal Accuracy')) if record['vertical_accuracy'] is not None: sfdcRecord.append( self.process_generate_field('vertical_accuracy', record['vertical_accuracy'], 'Vertical Accuracy')) return sfdcRecord def standard_fields_detail_record(self, complexFieldValue): sfdcRecord = [] if complexFieldValue['version'] is not None: sfdcRecord.append( self.process_generate_field('version', complexFieldValue['version'], 'Version')) if complexFieldValue['id'] is not None: sfdcRecord.append( self.process_generate_field('fulcrum_id', complexFieldValue['id'], 'Id')) if complexFieldValue['created_at'] is not None: sfdcRecord.append( self.process_generate_field('created_at', complexFieldValue['created_at'], 'Created At')) if complexFieldValue['updated_at'] is not None: sfdcRecord.append( self.process_generate_field('updated_at', complexFieldValue['updated_at'], 'Updated At')) if complexFieldValue['created_by_id'] is not None: sfdcRecord.append( self.process_generate_field('created_by_id', complexFieldValue['created_by_id'], 'Created By Id')) if complexFieldValue['updated_by_id'] is not None: sfdcRecord.append( self.process_generate_field('updated_by_id', complexFieldValue['updated_by_id'], 'Updated By Id')) if complexFieldValue['created_duration'] is not None: sfdcRecord.append( self.process_generate_field( 'created_duration', complexFieldValue['created_duration'], 'Created Duration')) if complexFieldValue['updated_duration'] is not None: sfdcRecord.append( self.process_generate_field( 'updated_duration', complexFieldValue['updated_duration'], 'Updated Duration')) if complexFieldValue['edited_duration'] is not None: sfdcRecord.append( self.process_generate_field( 'edited_duration', complexFieldValue['edited_duration'], 'Edited Duration')) if complexFieldValue['changeset_id'] is not None: sfdcRecord.append( self.process_generate_field('changeset_id', complexFieldValue['changeset_id'], 'Change Set ID')) if complexFieldValue['geometry'] is not None: sfdcRecord.append( self.process_generate_field( 'location', complexFieldValue['geometry']['coordinates'][1], 'Latitude')) sfdcRecord.append( self.process_generate_field( 'location', complexFieldValue['geometry']['coordinates'][0], 'Longitude')) return sfdcRecord # Fulcrum Record and SFDC Parent Record ID (prefix and postfix added) def generate_sfdc_fulcrum_detail_records(self, record): print '.......................................' print 'Processing Fulcrum Detail Records...' sfdcRecords = [] for fieldId in record['form_values']: fieldValue = record['form_values'][fieldId] isListField = isinstance(fieldValue, list) if isListField == True: complexFieldType = fieldValue[0] isRepeatingSections = self.checkKey(complexFieldType, 'form_values') if isRepeatingSections == True: sfdcInsertRecord = '' objectId = _sfdcPrefix + record['form_id'][0:13].replace( '-', '_') + '_' + fieldId + '_d__c' objectReferenceId = _sfdcPrefix + record['form_id'][ 0:13].replace('-', '_') + '_' + fieldId + '_d__r' for complexFieldValue in fieldValue: print '.......................................' print 'Processing Detail Record...' print ' Object: ' + objectId print ' ReferenceName: ' + objectReferenceId sfdcRecord = self.standard_fields_detail_record( complexFieldValue) complexFormValues = complexFieldValue['form_values'] sfdcFields = self.generate_detail_fields( complexFormValues) objectIdString = '"' + objectId + '"' recordIdString = '"' + complexFieldValue['id'] + '"' #sfdcRecord = json.dumps (sfdcRecord).replace('[','').replace(']','').replace('{','').replace('}','') sfdcRecord = json.dumps(sfdcRecord).replace( '[', '').replace(']', '').replace('{', '').replace('}', '') sfdcRecord = """, { "attributes": {"type" : """ + objectIdString + """ , "referenceId": """ + recordIdString + """ }, """ + sfdcRecord + ',' + sfdcFields + """ }""" sfdcInsertRecord += sfdcRecord objectReferenceIdString = '"' + str( objectReferenceId) + '"' sfdcInsertRecord = sfdcInsertRecord.replace(',', "", 1) recordJson = objectReferenceIdString + """:{"records":[""" + sfdcInsertRecord + """]}""" sfdcRecords.append(recordJson) return sfdcRecords
from fulcrum import Fulcrum import pyautogui import rpa import os import pandas as pd import sqlalchemy print('Welcome, my friend. Libraries imported.') fulcrum = Fulcrum(key=os.environ['FULCRUM_API']) print('\n Fulcrum API connection established.') export_dir = r'C:\Data\fmatic' os.chdir(export_dir) db_host = "postgresqlsdsu.postgres.database.azure.com" db_name = "fac_data_warehouse" db_user = os.environ['AZURE_PG_UKEY'] db_password = os.environ['AZURE_PG_PW'] sslmode = "require" #Production Engine engine = sqlalchemy.create_engine('postgresql+psycopg2://{}:{}@postgresqlsdsu.postgres.database.azure.com/fac_data_warehouse'.format(db_user, db_password)) print("Azure Connection established"+'\n' + '=================================')
# Change the names of the files below. New kml file will be called 'updated_kml.kml' # Need API access from fulcrum and the Fulcrum pyhton library installed. # This script and the kml file need to be in the same folder. from fastkml import kml from fulcrum import Fulcrum import sys import getopt fullCMDArguments = sys.argv fulcrum = Fulcrum(key=fullCMDArguments[6]) # add API your API key kmlfile = fullCMDArguments[2] # name of kml file. with open(kmlfile, 'rt') as file: doc = file.read() k = kml.KML() k.from_string(doc) features = list(k.features()) f2 = list(features[0].features()) f3 = list(f2[0].features()) # fieldKey can be updated to any title key, key or multiple keys within your form. # View the form definition by constructing the following URL and pasting it # into your browser: # https://api.fulcrumapp.com/api/v2/forms/YOUR-FORM-ID.json?token=YOUR-API-KEY # In the returned form definition JSON file, search for the key within form_values # and copy the value. If you want to display additional information in the name # of your pins, make note of the key values that match up with the
def setUp(self): self.fulcrum_api = Fulcrum(key=key)
import sqlite3 from fulcrum import Fulcrum conn = sqlite3.connect('photodb') cur = conn.cursor() formid = '' fulcrum = Fulcrum(key='') print("Starting to Sync photos") for (photo_id, filename, lat, lon, alt, created_on, uploaded, speed) in cur.execute('SELECT * FROM photos WHERE uploaded=0'): photo = fulcrum.photos.create('/home/pi/picard/pics/%s' % filename) print("Photo uploaded") obj = { "record": { "form_id": formid, "latitude": lat, "longitude": lon, "altitude": alt, "speed": speed, "form_values": { '4cf9': [{ 'photo_id': photo['photo']['access_key'] }] } } } record = fulcrum.records.create(obj) print("Record created") cur.execute('UPDATE photos set uploaded=1 where id=%s' % photo_id)
from sqlalchemy import create_engine, Column, Integer, String, inspect, Numeric, Time, Date, Sequence, ARRAY, DateTime from sqlalchemy.sql import text from sqlalchemy.ext.declarative import declarative_base import pandas as pd from dotenv import load_dotenv import io import os from pangres import upsert import re # get os env load_dotenv() # set the fulcrum token token = os.getenv('TOKEN') fulcrum = Fulcrum(key=token) # production postgresql db engine = create_engine(os.getenv('DBSTRING'), echo=False, pool_size=10, max_overflow=20) # get all the forms from the config app forms = fulcrum.query( 'SELECT form_id,app_name, create_spatial_view FROM "form_uuid" WHERE _status = \'enabled\'' ) # get all the form ids form_ids = forms['rows']