Vos données à votre portée avec Salesforce, Python, SQL, & et plus

Need event music? 🎸

Live and recorded jazz, pop, and meditative music for your virtual conference / Zoom wedding / yoga class / private party with quality sound and a smooth technical experience

Python pour Salesforce: compte -> campagne

07 Mar 2019 🔖 python tutoriels salesforce
💬 FR

Post Header Image

Table de matières

Aujourd’hui, on complique une tâche Salesforce très simple en Excel pour voir comment achever le même but avec Python.

La tâche, c’est de constituer une campagne à partir d’une liste des contacts associés à un compte.

Le code n’est pas trop difficile si vous lisez confortablement les champs de formule très compliqués.

Le niveau des explications est … disons … “débutant” mais pas “tout débutant” ! 😆

Si vous aimez apprendre des choses en copiant-collant des exemples, et en devinant un peu comment ils fonctionnent, vous trouverez ce code “niveau débutant.” Sinon, plutôt “débutant-intermédiat” ! 😊

Introduction

Récemment sur les forums de success Salesforce, on a demandé :

« Savez-vous s’il y a un moyen de constituer une campagne à partir d’une liste de compte ? »

L’approche facile en Excel …

Bien sûr, la tâche n’est pas trop difficile avec Data Loader et Microsoft Excel.

  1. On exporte un rapport en forme de CSV tous les contacts qui travaillent chez une compte. Il ne faut qu’une seule colonne dans le tableau : “Id(du contact).
  2. On ouvre le fichier CSV avec Microsoft Excel.
  3. On renomme la colonne “Id” à “ContactId”.
  4. On ajoute une deuxième colonne “CampaignId” et remplit toutes ces cellules du valeur “(quelque ID Salesforce d'une campagne)
  5. On ajoute une troisième colonne “Status” et remplit toutes ces cellules du valeur “(quelque phrase qui est un statut valide pour la campagne)
  6. On enregistre le fichier CSV
  7. On importe le nouveau fichier CSV (opération “insert“) à la table “membre de campagne”.

Apprenons l’approche difficile avec Python !

Comme je dis souvent … ne tranchissez pas du pain avec une tronçonneuse. C’est du temps perdu.

Trancher du pain avec une tronçonneuse

Mais de l’autre côté … il faut avoir des petites problèmes pour apprendre à utiliser la tronçonneuse !

Et trancher du pain avec une tronçonneuse … cela semble un peu amusant, n’est-ce pas ?

Alors voyons comment arriver au même but avec Python.

Cautions mot de passe

Pour opérer ce code, il faut y saisir des secrets comme votre mot de passe Salesforce, votre nom d’utilisateur Salesforce, et votre jeton de sécurité Salesforce.

Ce n’est pas bon !

Donc …

  1. N’exécutez ce code qu’avec un ordinateur auquel vous avez confiance (ne servez-vous pas d’un “IDE” en ligne comme Repl.it ou CodeBunk)
  2. N’exécutez ce code qu’avec un réseau internet auquel vous avez confiance (pas avec le WiFi de l’aeroport !)
  3. Si vous enregistrez ce code dans un fichier, mettez dans le nom du fichier “CONTIENT MON MOT DE PASSE” pour que vous vous souvenez de supprimmer TOUTES les données que j’ai mis en majuscules dans le code.
  4. N’enregistrez jamais ce code sur votre disque dur avec ces secrets toujours dans le code.

2 approches

Il y a deux programmes un peu pareils que nous allons examiner.

Similarités

Les deux vont se servir d’un “module” Python qui fournit des commandes pour correspondre avec une organisation Salesforce, “Simple Salesforce.”

  • Aux deux, on va stocker les résultats d’une requête SOQL dans un “variable” (1, 2) Python appelé “contacts”.
  • Aux deux, on va créer un variable Python “membresdecampagne” et le passer à Salesforce pour insérrer dans la table “membres de campagne”

La différence

La différence, c’est comment notre code va transformer les contenus de “contacts” jusqu’aux contenus de “membresdecampagne”.

“Simple Salesforce” rend notre requête de “contacts” ainsi:

[
	OrderedDict(
		[
			(
				'attributes', OrderedDict(
					[
						('type', 'Contact'),
						('url', '/services/data/v38.0/sobjects/Contact/003111111111111111')
					]
				)
			),
			('Id', '003111111111111111')
		]
	),
	OrderedDict(
		[
			(
				'attributes', OrderedDict(
					[
						('type', 'Contact'),
						('url', '/services/data/v38.0/sobjects/Contact/003222222222222222')
					]
				)
			),
			('Id', '003222222222222222')
		]
	)
]

Mais Simple Salesforce demande que membresdecampagne soit ainsi pour insérrer des membres de campagne dans notre base de données Salesforce:

[
	{
		'ContactId': '003111111111111111',
		'CampaignId': '701777777777777777',
		'Status': 'Sent'
	},
	{
		'ContactId': '003222222222222222',
		'CampaignId': '701777777777777777',
		'Status': 'Sent'
	}
]
  • Les “[]” indiquent des “listes” Python (1, 2)
  • Les “{}” indiquent des “dictionnaires” Python

Heureusement, Python nous offre deux moyens assez concis d’effectuer cette transformation, que nous éxaminerons aux paragraphes suivantes.

Code n° 1

from simple_salesforce import Salesforce
import json

nomdutilisateur = 'VOTRE_NOM_D_UTILISATEUR'
motdepasse = 'VOTRE_MOT_DE_PASSE'
jetondesecurite = 'VOTRE_JETON'
idducompte = 'ID_SALESFORCE_DU_COMPTE__COMMENCE_AVEC_001'
iddelacampagne = 'ID_SALESFORCE_DE_LA_CAMPAGNE__COMMENCE_AVEC_701'
statut = 'DU_TEXTE_QUI_EST_UN_STATUT_VALIDE_POUR_LA_CAMPAGNE'

requete = "SELECT Id FROM Contact WHERE AccountId='" + idducompte + "'"

sfsession = Salesforce(username=nomdutilisateur, password=motdepasse, security_token=jetondesecurite)

contacts = sfsession.query_all(requete)['records']
print('Il y a ' + str(len(contacts)) + ' records dans la réponse à la requête')

membresdecampagne = []
for x in contacts:
    x2 = {k:v for k,v in x.items() if k != 'attributes'}
    x2['ContactId'] = x2.pop('Id')
    x2['CampaignId'] = iddelacampagne
    x2['Status'] = statut
    membresdecampagne.append(x2)

print('On contacte Salesforce pour saisir les données')
sfsession.bulk.CampaignMember.insert(membresdecampagne)
print('Fini')

Détail

Examinons en détail la partie “transformation de données” de notre premier programme :

membresdecampagne = []
for x in contacts:
    x2 = {k:v for k,v in x.items() if k != 'attributes'}
    x2['ContactId'] = x2.pop('Id')
    x2['CampaignId'] = iddelacampagne
    x2['Status'] = statut
    membresdecampagne.append(x2)
  1. On construit une liste vide et l’appelle “membresdecampagne’”.
  2. On boucle sur les membres de la liste “contacts”. Pour chaque membre “x” de la liste (qui est un “dictionnaire” et ne représente qu’un seul contact Salesforce) :
    • On en fait une copie, sans les informations sous l’etiquette “attributes”. On appelle la copie “x2”.
    • On renomme Id -> ContactId dans x2
    • On ajoute CampaignId à x2 (avec un valeur de 'ID_SALESFORCE_DE_LA_CAMPAGNE__COMMENCE_AVEC_701')
    • On ajoute Status à x2 (avec un valeur de 'DU_TEXTE_QUI_EST_UN_STATUT_VALIDE_POUR_LA_CAMPAGNE')
    • On ajoute x2 à la fin de la liste “membresdecampagne’”.

Code n° 2

from simple_salesforce import Salesforce
import json

nomdutilisateur = 'VOTRE_NOM_D_UTILISATEUR'
motdepasse = 'VOTRE_MOT_DE_PASSE'
jetondesecurite = 'VOTRE_JETON'
idducompte = 'ID_SALESFORCE_DU_COMPTE__COMMENCE_AVEC_001'
iddelacampagne = 'ID_SALESFORCE_DE_LA_CAMPAGNE__COMMENCE_AVEC_701'
statut = 'DU_TEXTE_QUI_EST_UN_STATUT_VALIDE_POUR_LA_CAMPAGNE'

requete = "SELECT Id FROM Contact WHERE AccountId='" + idducompte + "'"

sfsession = Salesforce(username=nomdutilisateur, password=motdepasse, security_token=jetondesecurite)

contacts = sfsession.query_all(requete)['records']
print('Il y a ' + str(len(contacts)) + ' records dans la réponse à la requête')

import pandas
contactsdicts = [{k:v for k,v in d.items() if k !='attributes'} for d in contacts]
df = pandas.DataFrame(contactsdicts)
df.rename(columns={'Id':'ContactId'}, inplace=True)
df['CampaignId'] = iddelacampagne
df['Status'] = statut
membresdecampagne = json.loads(df.to_json(orient='records'))

print('On contacte Salesforce pour saisir les données')
sfsession.bulk.CampaignMember.insert(membresdecampagne)
print('Fini')

Détail

Examinons en détail la partie “transformation de données” de notre second programme :

import pandas
contactsdicts = [{k:v for k,v in d.items() if k !='attributes'} for d in contacts]
df = pandas.DataFrame(contactsdicts)
df.rename(columns={'Id':'ContactId'}, inplace=True)
df['CampaignId'] = iddelacampagne
df['Status'] = statut
membresdecampagne = json.loads(df.to_json(orient='records'))
  1. On importe une autre “module” qui s’appelle “pandas” et qui s’occupe des données en forme de tableau (“DataFrame“)
  2. On fait une copie de la liste “contacts” mais sans l’information sous “attributes” pour chaque membre de la liste. On appelle la copie “contactsdicts
  3. On crée un tableau qui contient tous les membres de la liste “contactsdicts”. On appelle ce tableau “df”.
    • Ce tableau n’a qu’une seule colonne, “Id”, parce que l’on n’a exporté en SOQL que la colonne “Id.”
    • Ce tableau a une ligne pour chaque membre de la liste “contactsdicts” (avec la valeur “003…”).
  4. On renomme l’etiquette de colonne Id à ContactId dans df.
  5. On ajoute une colonne CampaignId au tableau “df” et remplit toutes ses cellules avec ‘ID_SALESFORCE_DE_LA_CAMPAGNE__COMMENCE_AVEC_701’
  6. On ajoute une colonne Status au tableau “df” et remplit toutes ses cellules avec ‘DU_TEXTE_QUI_EST_UN_STATUT_VALIDE_POUR_LA_CAMPAGNE’
  7. On exporte les contenus du tableau “df” dans le format demandé par “Simple Salesforce” et appelle cette sortie “membresdecampagne

Allez-y, essayez l’approche difficile !

  1. Créez un “dev org” Salesforce.
  2. Remplissez-le de quelques comptes / contacts / campagnes.
  3. Installez Python et Simple Salesforce sur votre ordinateur.
  4. Essayez ce code chez vous.

Ressources et liens

--- ---