Python pour Salesforce: compte -> campagne
07 Mar 2019
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.
- 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). - On ouvre le fichier CSV avec Microsoft Excel.
- On renomme la colonne “
Id
” à “ContactId
”. - On ajoute une deuxième colonne “
CampaignId
” et remplit toutes ces cellules du valeur “(quelque ID Salesforce d'une campagne)
” - On ajoute une troisième colonne “
Status
” et remplit toutes ces cellules du valeur “(quelque phrase qui est un statut valide pour la campagne)
” - On enregistre le fichier CSV
- On importe le nouveau fichier CSV (opération “insert“) à la table “membre de campagne”.
- Soit avec Data Loader (instructions)
- Soit avec DataLoader.io
Apprenons l’approche difficile avec Python !
Comme je dis souvent … ne tranchissez pas du pain avec une tronçonneuse. C’est du temps perdu.
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 …
- 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)
- N’exécutez ce code qu’avec un réseau internet auquel vous avez confiance (pas avec le WiFi de l’aeroport !)
- 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.
- 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)
- On construit une liste vide et l’appelle “
membresdecampagne
’”. - 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
dansx2
- 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
’”.
- On en fait une copie, sans les informations sous l’etiquette “
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'))
- On importe une autre “module” qui s’appelle “
pandas
” et qui s’occupe des données en forme de tableau (“DataFrame
“) - 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
” - 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…”).
- Ce tableau n’a qu’une seule colonne, “
- On renomme l’etiquette de colonne
Id
àContactId
dansdf
. - On ajoute une colonne
CampaignId
au tableau “df
” et remplit toutes ses cellules avec ‘ID_SALESFORCE_DE_LA_CAMPAGNE__COMMENCE_AVEC_701’ - On ajoute une colonne
Status
au tableau “df
” et remplit toutes ses cellules avec ‘DU_TEXTE_QUI_EST_UN_STATUT_VALIDE_POUR_LA_CAMPAGNE’ - 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 !
- Créez un “dev org” Salesforce.
- Remplissez-le de quelques comptes / contacts / campagnes.
- Installez Python et Simple Salesforce sur votre ordinateur.
- Essayez ce code chez vous.
Ressources et liens
- Comment installer Python sur un ordinateur Windows avec la suite de programmes “Anaconda” (en anglais – j’espère finir bientôt la version française)
- Usage de “Simple Salesforce” en Python - guide officiel (en anglais).
- Comment installer “Simple Salesforce” sur votre ordinateur (en anglais)
- Les “variables” et comment les affecter en Python sur numworks.com
- Les “variables” et comment les affecter en Python par Denis LE FUR
- Création des “listes” en Python par Denis LE FUR
- Manipulation des “listes” avec Python par Denis LE FUR
- Usage des “dictionnaires” en Python
- Une initiation à Python Pandas par Raphaël da Silva
- Modification des tableaux “DataFrame” avec Python Pandas sur python-simple.com (notez: il y a deux barres de défilement verticale – n’oubliez pas de tirer sur la barre intérieur pour voir tous les contenus).
- Un “DataFrame” est le mot technique pour un tableau de données quand on se sert de la partie de Python qui s’appelle “Pandas”.
- Tout sur les “DataFrames” en Python Pandas sur kaggle.com.
- Un “DataFrame” est le mot technique pour un tableau de données quand on se sert de la partie de Python qui s’appelle “Pandas”.
- Tout sur les “Séries” en Python Pandas sur kaggle.com.
- Une “Série” est le mot technique pour un enregristement ou une colonne des données d’un tableau quand on se sert de la partie de Python qui s’appelle “Pandas”.