Salesforce
Salesforce Connectorは、Salesforce組織の標準オブジェクト、カスタムオブジェクト、ファイルを読み、レコードを書き戻し、ファイルを保存し、リードの変換のような組織の操作を実行します。解約リスクの例に出てくるConnectorがこれです。取引先を読み、DWHのデータとJOINし、LLMに判定させ、その結果で更新します。
読み取り元
接続ユーザーが参照できるすべてのオブジェクトが読み取り元で、API参照名の小文字で参照します。salesforce.accounts、salesforce.contacts、salesforce.opportunities、salesforce.cases、カスタムオブジェクトなら salesforce.subscriptions__c のようになります。列はオブジェクトの項目で、組織のメタデータから検出されるので、Salesforce側で項目を足せば、Connectorを変えなくても列として使えます。すべてのオブジェクトのキーは Id です。
ファイルも読み取り元です。salesforce.files はContentVersionのレコードを、resource、version(ContentVersionのid。新しいバージョンごとに変わる)、title、file_extension、size、linked_to(ファイルが添付されているレコード)とともに一覧し、resource と version でJOINした salesforce.contents がファイルを content_ref として読みます。
項目レベルセキュリティが適用されます。連携ユーザーに見えない項目は列になりません。その項目を指定したプログラムは check で失敗します。
型
| Salesforce | ActQL | 備考 |
|---|---|---|
Id、参照関係、主従関係 | string | 18文字のid |
| テキスト、テキストエリア、ロングテキスト、リッチテキスト、URL、メール、電話 | string | リッチテキストはHTMLを保つ |
| 数値(p, s)、通貨、パーセント | decimal(p, s) | 精度とスケールは項目に宣言されたもの |
| チェックボックス | bool | |
| 日付 | date | |
| 日付/時間 | timestamp | UTCの時点。Salesforceはゾーンを保存しない |
| 時間 | time | |
| 選択リスト | string | 値のAPI参照名。選択リストにない値の書き込みは、項目が制限なしでない限り、その項目を失敗させる |
| 複数選択リスト | string の array | Connectorが ; で分割・結合する |
| 自動採番、数式、積み上げ集計 | その結果の型 | 読み取りのみ。書き込みは check で失敗する |
| 地理位置情報 | latitude と longitude を持つ object | |
| 住所(複合) | object | 1つのオブジェクトとして読み、構成要素の項目を通して書く |
| Base64(ContentVersionのデータ) | content_ref | salesforce.contents を通してのみ |
書き込みは同じ規則で逆方向に変換します。項目に収まらない値は、静的に分かるなら check で、そうでなければその項目が失敗します。
Effectと操作
レコードのEffectはキーで書き、オブジェクトはAPI参照名で指定します(salesforce.Account)。
- insert —
EFFECT INSERT salesforce.Account (Name, Industry, …) VALUES (…)。 - update —
EFFECT UPDATE salesforce.Account ID id SET (…)。 - upsert —
EFFECT UPSERT salesforce.Account ID External_Id__c SET (…)。キーは外部IDとしてマークされた項目で、Salesforceはそれで照合し、一致するものがなければレコードを作成します。 - delete —
EFFECT DELETE salesforce.Account ID id。
ID で指定するキーは、ちょうど1レコードを識別しなければなりません。Id は常にそうです。外部IDの項目は宣言によって一意で、外部IDとしてマークされていない項目はConnectorが check で拒否します。同じキーに対して元のレコードが2つの異なる値を持つ更新は、check で拒否されます。
ファイル:
- store —
EFFECT STORE salesforce.files SET (title = …, content = content, linked_to = account_id)は、レコードのcontent(SERIALIZEまたはcontentsの読み取り元から来たもの)からContentVersionを作り、指定したレコードに関連付けます。
操作:
- convert_lead —
EFFECT COMMAND salesforce.convert_lead TARGET lead_id ID lead_id INPUT (account_id = …, opportunity_name = …, converted_status = 'Qualified')は、リードを取引先、取引先責任者、そして任意で商談に変換します。 - send_email —
EFFECT COMMAND salesforce.send_email ID key INPUT (template = 'Renewal_Reminder', to = contact_id, what = opportunity_id)は、Salesforceのメールテンプレートを通して、取引先責任者またはリードにメールを送ります。
セットアップ
"salesforce": {
"connector": "salesforce",
"instance_url": "https://acme.my.salesforce.com",
"api_version": "v62.0",
"credentials": {"access_token": {"env": "SALESFORCE_ACCESS_TOKEN"}}
}アクセストークンは連携ユーザーのものです。代わりに、JWTベアラーフローの接続アプリケーション(credentials.jwt_private_key と credentials.client_id)を使うと、Hostがトークンを自分で更新します。そのユーザーには、プログラムが読むすべてのオブジェクトと項目への参照権限、書くオブジェクトへの作成・編集・削除権限、そして操作のための「リードの変換」と「メールの送信」の権限が必要です。ActQLは、実行するプログラムに必要なもの以上を求めません。さらにHostのポリシーで、オブジェクトと操作ごとに絞ることもできます。
ActQL Cloudでは、SalesforceはCloudのホスト型OAuthアプリケーションを通して接続します。そのアプリケーションがあなたの組織で承認されるまでは、ローカルのHostと同じトークンまたはJWTの設定がそのまま使えます。
Capabilityとプッシュダウン
| 演算 | プッシュダウンされる条件 |
|---|---|
| 列の選択 | 常に。参照される項目だけを選ぶ(SOQLの SELECT) |
WHERE | 述語が1つのオブジェクトの項目と、SOQLでもActQLと同じ意味で評価される演算子だけを使うとき。=、!=、<、>、IN、LIKE(SOQLでは大文字小文字を区別しないので、区別する LIKE はHostに残る)、IS NULL、日付リテラル。複数のオブジェクトや読み取り元にまたがる述語はエンジンに残すか分割し、残りはHostが評価する |
ORDER BY、LIMIT | 並べ替えがSOQLで順序付けできる項目(ロングテキストと複数選択リストを除く)に対するもので、件数が定数かパラメーターのとき |
| 集計 | COUNT、COUNT(DISTINCT)、SUM、AVG、MIN、MAX と、グループ化できる項目での GROUP BY。SOQLの集計の上限2,000レコードの範囲内。それ以外は取得したレコードに対してHostで集計する |
JOIN | Salesforceの中では行わない。関連項目はidの列として読み、JOINはエンジンで実行する |
explain は、プッシュダウンされたステップをSite connector:salesforce、Interface Salesforce API で表示します。
プレビューと突き合わせ
プレビュー。 更新、UPSERT、削除は full_diff でプレビューします。Connectorは対象のレコードをキーで読み、現在の項目の値と各レコードの SystemModstamp を記録し、プレビューには項目ごとに現在の値と新しい値が出ます。適用時の書き込みは、その SystemModstamp に対する If-Unmodified-Since の条件を持ちます。プレビューと適用の間に変わったレコードは更新されません。その項目は failed(conflict)で終わり、続けるよう求められればRunは新しいプレビューを作ります。追加とファイルの保存は targeted でプレビューします。作成されるレコードまたはファイルを、すべての項目の値とともに示します。リードの変換は、リード、作成またはマージ先となる取引先と取引先責任者、ステータスをプレビューします。メールは、テンプレート、宛先、関連レコードをプレビューします。
突き合わせ。 すべての書き込みは、Connectorが送信前に生成してEffectの項目に対して記録したジョブまたはリクエストのIDのもとで、Composite APIかBulk API 2.0を通して送ります。リクエストの各レコードは、接続で指定した専用の項目(組織にあれば ActQL_Request__c)、またはBulkジョブの外部参照にマーカーを持ちます。応答が失われたら、そのジョブやCompositeリクエストをIDで取得し、レコードごとの結果を読んで突き合わせます。期待どおりの値を持つレコードや、LastModifiedDate が送信後のレコードは、それだけでは証跡になりません。リードの変換は、リードの IsConverted、ConvertedAccountId とリクエストのマーカーで突き合わせます。メールは、Salesforceが送信時に作る EmailMessage のレコードで突き合わせます。これらで結果が確定しなければ、項目は unknown のままで、何も再送しません。操作は、Salesforceがメールをキューに入れた、または変換を開始した時点で accepted、結果のレコードが存在すれば applied、どちらも確定できなければ unknown で終わります。
上限と費用
- 読み取りはAPIによってページングされます(SOQLは1ページ2,000レコード)。Connectorはプログラムの件数の上限までページをたどり、途中までの結果を返すのではなくエラーで止まります。
- Salesforceの1日あたりのAPIリクエスト数の上限は、その組織を使うすべてのものと共有です。上限を超えそうなプログラムは、送信を始める前に失敗します。残りの割り当てをやみくもに消費することはありません。Bulk API 2.0のジョブは別に数えられ、Composite APIの1バッチ200レコードを超えるEffectに使われます。
- ファイルの内容はプログラムのバイト数の上限で抑えられます。それより大きいContentVersionは、途中まで読まれるのではなく拒否されます。RESTの上限(2 GB)を超えるアップロードは
checkで拒否されます。 - メールの送信は、組織の1日あたりの個別メール送信数の上限を消費します。超えそうなプログラムは送信前に失敗します。
例
利用が落ちている取引先を読みます。
SELECT a.id, a.name, a.description
FROM salesforce.accounts AS a
JOIN snowflake.usage_30d AS u ON a.id = u.account_id
|> WHERE u.trend = 'down'
|> ORDER BY a.name;取引先ごとに解約リスクを判定し、書き戻します。
SELECT a.id AS id, a.description AS notes,
u.active_users, u.trend
FROM salesforce.accounts AS a
JOIN snowflake.usage_30d AS u ON a.id = u.account_id
|> INFER `model-task:churn-risk.v1`
INPUT (notes, active_users, trend) AS risk
|> WHERE risk.outcome = 'ok' AND risk.value.level = 'high'
|> RESULT updates
|> EFFECT UPDATE salesforce.Account
ID id SET (
Churn_Risk__c = risk.value.level,
Risk_Reason__c = risk.value.reason
);ポリシーが求めれば、この更新はCheckpointで止まります。プレビューには取引先ごとに、Churn_Risk__c と Risk_Reason__c の現在の値と新しい値が並びます。
LLMが見込みありと判定したリードを変換します。
FROM salesforce.leads AS l
|> WHERE l.status = 'Working' AND l.is_converted = FALSE
|> INFER `model-task:lead-qualification.v1`
INPUT (company = l.company, notes = l.description) AS q
|> WHERE q.outcome = 'ok' AND q.value.qualified
|> EFFECT COMMAND salesforce.convert_lead TARGET l.id ID l.id
INPUT (converted_status = 'Qualified', opportunity_name = l.company || ' - new business');Source: actql/actql/docs/connectors/salesforce.md at d904416674e4 · Edit on GitHub