見出し画像

SalesforceにGoogleドライブからAPI経由でPDFやExcelなどのファイルをアップする

やり方分からなくなりそうだったのでほぼ自分用のメモです。

見積書・請求書などのテンプレートをスプレッドシートとしてドライブ上に用意しておいて、Salesforceの商談のカスタムボタンを押して、レコードの内容をもとに見積書・請求書のPDFをドライブ上に作って、それをSalesforceにファイルとしてアップするみたいなことを想定してます。

内容としてはこのヘルプをGAS用にカスタマイズした感じです。

Salesforceでのファイルの概念

Content DocumentとContent Versionという概念があります。僕もあまり理解しきれていませんが、ざっくり言うとこんな感じだと思います。

Content Document
商談など他のオブジェクトと関連付けるためのファイルの概念。ファイルをバージョン管理することができるので、1つのContent Documentに新しいContent Versionを紐付けることで、他のオブジェクトとの関連はそのままで中身を差し替えることが可能。

Content Version
ファイルの実体。Content Documentに関連付けられる。

ファイルの扱い方

Blob(バイナリデータ)として扱います。ざっくり言うと、PDFや画像ファイルなどをバイト列とみなして扱う方法です。こちらの記事が分かりやすかったです。

対応しているファイルは こちらのGAS公式リファレンス が参考になります。pdfだけでなく、gif, jpg, png, csv, txt, xlsx, docx, pptx, zipなどなどが扱えます。動画は無理ですが、かなり幅広い種類のファイルに対応しています。

GASのコード

function uploadFile() {

 //SalesforceのAPIとの接続確認
 checkAuthorization();
 var prop = PropertiesService.getScriptProperties();
 var sessionInfo = JSON.parse(prop.getProperty("session_info"));

 //ドライブ上からPDFを取得する
 var pdf = DriveApp.getFileById('*****************');  //PDFファイルのドライブ上のID
 var blob = pdf.getBlob();  //PDFをBlobオブジェクトとして取得
 var bytes = blob.getBytes();  //Blobのバイト列を取得
 var enBytes = Utilities.base64Encode(bytes);  //取得したバイト列をエンコード

 //Salesforceにアップロードするためのbodyを作成
 var cvJson = {
   "Title" : "アップロードテストファイル",  //アップされるファイルのタイトル
   "PathOnClient" : "test.pdf",  //拡張子が.pdfになっていないとプレビューが正しく表示されない。拡張子の前は(多分)何でも大丈夫。PDF以外のファイルの場合はxlsxなどそれぞれの拡張子を設定
   "VersionData" : enBytes
 };

 //Salesforceにcontent versionとしてアップして、アップされたファイルのcontent version IDを取得
 var cvResponse = UrlFetchApp.fetch(sessionInfo.instance_url + "/services/data/v51.0/sobjects/ContentVersion", {
   "method" : "POST",
   "contentType": "application/json",
   "headers" : {
     "Authorization": "Bearer " + sessionInfo.access_token
   },
   "payload" : JSON.stringify(cvJson)
 });
 var jsonCvResponse = JSON.parse(cvResponse.getContentText());
 var cvId = jsonCvResponse.id;

 //content versionに紐付いて作成されたcontent documentのIDを取得
 var query = "SELECT+ContentDocumentId+FROM+ContentVersion+WHERE+Id+=+'" + cvId + "'"
 var cdResponse = UrlFetchApp.fetch(sessionInfo.instance_url + "/services/data/v51.0/query/?q=" + query, {
   "method" : "GET",
   "contentType": "application/json",
   "headers" : {
     "Authorization": "Bearer " + sessionInfo.access_token,
   }
 });
 var jsonCdResponse = JSON.parse(cdResponse.getContentText());
 var cdRecords = jsonCdResponse["records"];
 var jsonCdRecords = JSON.parse(JSON.stringify(cdRecords));
 var cdId = jsonCdRecords[0].ContentDocumentId;

 //商談レコードとリンクさせるためのbodyを作成
 var linkJson = {
   "ContentDocumentId" : cdId,
   "LinkedEntityId" : "*************", //商談のレコードID
   "Visibility" : "AllUsers" //閲覧できる人の制限
 };

 //商談レコードとファイルをリンクさせる
 var linkResponse = UrlFetchApp.fetch(sessionInfo.instance_url + "/services/data/v51.0/sobjects/ContentDocumentLink", {
   "method" : "POST",
   "contentType": "application/json",
   "headers" : {
     "Authorization": "Bearer " + sessionInfo.access_token
   },
   "payload" : JSON.stringify(linkJson)
 });

 Logger.log(linkResponse);

}

APIのアクセストークン部分に関してはこちらにまとめています。

PathOnClientの部分は拡張子「.pdf」をつけておかないとこんな感じで同じデータをアップしても正しく読み取ってくれませんでした。

ファイル___Salesforce

やっていること

細かいことはコード内のコメントで記載しています。

ドライブのPDFファイルからBlobとしてbyteデータを取得

byteデータをSalesforceのContent Versionとしてアップ(同時にContent Documentも作成される)

作成されたContent Documentを商談レコードと紐付ける

今後

・商談レコードからパラメータを渡してファイルの内容をカスタマイズする
前回の記事と同じやり方で可能

・申請まで一気通貫でできるようにしたい
→これを参考にやればできそう

Contact

何か気になることがありましたら twitter@takahirostone までお気軽にご連絡ください!


よろしければサポートお願いします!そのうちオリジナルドメインにしたいなと思っているのでその資金にさせていただきます!