Zoho CRMの「入力値の関連付け」とは、ワークフロールールから呼び出すDeluge関数の引数(関数が受け取る値)に、どのレコードのどの項目を渡すかを決める設定です(公式ドキュメント)。Delugeは、Zoho CRMの中で動く独自のスクリプト言語です。ワークフローから関数を呼ぶ基本の形は、Deluge関数でタスクの自動生成を設定した記事で紹介しています。

この設定が空になっていると、関数は引数を受け取れないまま動きます。しかも、作り方によってはワークフローの実行結果が「成功」と表示されるため、処理が動いていないことに何日も気づけないことがあります。

本記事では、当社が支援している非営利の会員制団体のZoho CRMで実際に起きた事例をもとに、何が起きたか、どう気づいたか、どう直したか、再発をどう防ぐかをまとめます。

何が起きたか:フォームから入った申込で、自動処理が動いていなかった

この団体では、Zoho Formsの申込フォームから入ったデータをもとに、Zoho CRMのワークフローとDeluge関数で次のような処理を自動化していました。

  • フォームから作られた見込み客・担当者を、該当するキャンペーンに紐づける
  • 会員(取引先にあたるモジュール)が作られたら、入金の記録(商談にあたるモジュール)を自動で作る
  • 継続課金が作られたら、将来の入金予定を自動で作る

ある日、フォームから入った見込み客がキャンペーンに紐づいていないことが分かりました。関数の実行ログを開くと、入力値の欄は「-」で、ログには「レコードID: null」と出ていました。関数は GET /Leads/null のようにIDの部分が null のままレコードを取りにいき、取得に失敗して終了していました。

2日後には、別のフォームのテスト送信で同じ現象が起きました。今度は担当者のキャンペーン紐づけと、会員作成時の入金記録の自動生成が、どちらも引数 null のまま終わっていました。

原因は、ワークフロールール側の「入力値の関連付け」が空になっていたことでした。関数のコードにも、ルールの条件にも問題はありませんでした。

なぜ気づけなかったか:一覧の「成功」は業務の成功ではない

この件で一番の教訓は、ワークフローの実行結果に「成功」と出ていたことです。

関数は、レコードが取れなかったときに備えてエラー分岐(失敗したときの処理)を持っていました。引数が null でレコードが取れないと、関数はこのエラー分岐に入り、ログを残して自分で処理を終えます。関数としては「想定どおりに終わった」ので、ワークフローの実行状況には成功が1件と記録されます。

つまり、一覧の「成功」は関数の呼び出しが終わったことを示しているだけで、キャンペーンへの紐づけや入金記録の作成が終わったことは示していません。一覧だけを見ていると、失敗を見分けられません。

気づけたきっかけは2つでした。

  1. 関数のエラー分岐から管理者に通知メールを送る仕組みを入れていた
  2. 作られるはずのレコード(関連リストの入金記録、キャンペーンの紐づけ)が無いことを、画面で確かめた

逆に言えば、エラー分岐で通知を送らない関数だと、実行ログを開くまで誰も気づけません。

関数のコードを更新すると、関連付けは消えるのか

ワークフローから呼ぶ関数はコードとルール側の入力値の関連付けの二か所で成り立ち、関連付けが空だと引数が空のまま渡ってしまうことを示した図

手がかりは、コードを更新した関数と、関連付けが空になったルールが一致したことでした。調べると、関連付けが空になっていたルールには共通点がありました。呼び出している関数のコードを、少し前に本番で更新していたことです。

関数の種類 少し前のコード更新 点検時の入力値の関連付け
見込み客のキャンペーン紐づけ あり 空欄
担当者のキャンペーン紐づけ あり 空欄
会員作成時の入金記録の自動生成 あり 空欄
会員作成時の継続課金の自動生成 あり 空欄
継続課金作成時の入金予定の自動生成 あり 空欄
名刺データの名寄せ なし 設定済み

コードを更新していない関数だけが無傷だったため、当初は「関数のコードを更新して保存すると、ルール側の関連付けが消える」と考えました。

ところが、その後の修正で関数のコードを書き換えて保存したところ、関連付けは保持されていました。画面からの保存でも、APIからの更新でも消えませんでした。確かな事実は次の2つにとどまります。

  • ある時期にコードを更新した関数で、呼び出し元ルールの関連付けがそろって空になっていた
  • 別の日のコード更新では、関連付けは残っていた

更新すれば必ず消える、というわけではありません。消える条件は、当社では特定できていません。 Zohoの公式ドキュメントでも、関数を後から編集したときに関連付けがどうなるかの記載は、当社が確認した時点では見つかりませんでした。だからこそ、「更新したら毎回確かめる」という運用に落とし込みました。

対処1:有効なルールを全数点検する

1件見つかった時点で、同じ現象が他にもあると考えるのが安全です。この事例では、有効なワークフロールールを1件ずつ画面で開いて確かめました。

  1. 設定 → 自動化 → ワークフロールールを開き、有効なルールを一覧にする
  2. 関数を呼んでいるルールを1件ずつ開く
  3. アクションの関数を開き、「入力値の関連付け」の各引数に値が入っているかを見る
  4. 結果を表に残す(ルール名・引数名・点検時の値・対応)

6件中5件が空欄(うち1件は先に修正済み)、1件が正常でした。表に残しておくと、修正漏れを防げるうえ、あとで原因を考えるときの材料になります。

対処2:空になった関連付けはどう直すか(保存の順番に注意)

空欄だったルールは、次の手順で直しました。関数のコードは変えていません。

  1. ワークフロールールの関数アクションで、関数の設定画面を開く
  2. 空欄の引数の値欄で「#」を押す
  3. モジュール(例:担当者)を選び、ID項目(例:担当者ID)を選ぶ
  4. 「完了する」を押す
  5. 関数の設定画面で「保存する」を押す
  6. 最後にワークフロールールの「保存する」を押す
  7. もう一度ルールと関数の設定を開き、値(例:「担当者 - 担当者ID」)が残っていることを確かめる

関数の設定だけ保存してルールを保存し忘れると、変更が反映されないおそれがあります。保存は「関数→ルール」の順で、最後に開き直して確かめるところまでを1セットにしてください。

修正後、フォームからテスト送信し、実行ログの入力値欄に実際のレコードIDが入っていること、キャンペーンへの紐づけまで完了したことを確かめました。

同時に見つかった落とし穴:本番にサンドボックスのIDが残っていた

関連付けを直したあと、別のテスト送信で、今度は入金記録の作成だけが失敗しました。ログを見ると、入金記録を作るAPIが INVALID_DATA を返していました。

原因は、関数のコードに書いていたキャンペーンIDでした。本番の関数に、サンドボックス(検証用環境)側のIDが入っていたのです。サンドボックスと本番では、同じ設定のIDの末尾がそろい、先頭の部分だけが違っていました。サンドボックスから取り込んだ際に、先頭が置き換わらなかったものと見ています。サンドボックスから本番へ設定を移すときに検証用の値を持ち込まない手順は、Zoho CRMのSandboxから本番へ反映する落とし穴にまとめています。

さらに、この関数には次の欠陥もありました。

  • invokeurl(DelugeからAPIを呼ぶ命令)の応答の中身を確かめていなかった
  • 当社の環境では、APIがエラーを返しても invokeurl は例外を出さず、catch に入らなかった
  • そのため関数は「完了しました」と出して終わり、エラー通知も送られなかった

ここでも「成功と表示されるのに、処理はされていない」という同じ形の問題が起きていました。

なお、引数の対応付けが空になる不具合は、別のお客様の電子署名フローでも、ほかの原因と重なって起きていました。複数の原因が重なったときの切り分け方は、ワークフローで署名依頼が飛ばず請求書メールが先に届いた事例で紹介しています。

再発防止:関数側に入れておく3つの守り

関連付けが消える条件が分からない以上、関数の側で「おかしな状態なら知らせる」ようにしておくのが現実的です。

守り1:引数が空なら通知して止める

引数が空のまま先へ進まないよう、関数の冒頭で確かめます。null が文字列として渡るケースにも備えています。

void automation.LinkContactToCampaign(string contact_id)
{
	functionName = "LinkContactToCampaign";
	idText = ifnull(contact_id,"");
	if(idText.trim() == "" || idText == "null")
	{
		sendmail
		[
			from :zoho.adminuserid
			to :zoho.adminuserid
			subject :"[要確認] 関数の引数が空です:" + functionName
			message :"ワークフローから呼ばれましたが contact_id が空でした。ルールの「入力値の関連付け」を確認してください。"
		]
		info "引数が空のため終了します";
		return;
	}
	contact = zoho.crm.getRecordById("Contacts",idText.toLong());
	info contact.get("Last_Name");
	// 以降、本来の処理
}

通知先は例として管理者にしています。実際には、運用担当者のアドレスや、エラー通知用にまとめた関数を呼ぶ形に置き換えてください。

守り2:APIの応答を確かめてから「完了」とする

invokeurl でレコードを作ったら、応答の status が success かを確かめます。満たさなければ通知します。

response = invokeurl
[
	url :"https://www.zohoapis.jp/crm/v8/Deals"
	type :POST
	parameters:body.toString()
	connection:"crm_connection"
];
info response;
isSuccess = false;
dataList = response.get("data");
if(dataList != null && dataList.size() > 0)
{
	first = dataList.get(0);
	if(first.get("status") == "success")
	{
		isSuccess = true;
	}
}
if(!isSuccess)
{
	sendmail
	[
		from :zoho.adminuserid
		to :zoho.adminuserid
		subject :"[要確認] レコード作成に失敗しました"
		message :"API応答:" + response.toString()
	]
	return;
}
info "作成完了:" + dataList.get(0).get("details").get("id");

body は作成するレコードの内容を {"data": [ { ... } ]} の形で入れたマップです。接続名(connection)とAPIのドメインは、ご利用の環境に合わせて変えてください。

守り3:環境ごとにIDを切り替える

サンドボックスと本番でIDの先頭だけが違う環境では、組織変数などで環境を判定し、先頭部分を切り替える方法が使えます。当社の事例では、組織変数で「サンドボックスかどうか」を持たせ、IDの先頭を変数にして組み立てる形に直しました。IDの値そのものはご利用の環境で確かめてください。

関数を本番で更新したときのチェックリスト

この事例を受けて、関数を本番で更新・保存したら次の項目を確かめることにしました。

  1. 更新した関数を呼んでいるワークフロールールをすべて洗い出す
  2. 各ルールの関数アクションを開き、「入力値の関連付け」がすべて埋まっているかを見る
  3. 空欄があれば「#」→モジュール→ID項目で設定し直し、関数→ルールの順で保存する
  4. 保存後にもう一度開いて、値が残っていることを確かめる
  5. テストデータで実際に発火させ、実行ログの入力値欄に本物のIDが入っていることを見る
  6. 作られるはずのレコード(関連リスト・キャンペーンの紐づけなど)を画面で確かめる
  7. コード内のレコードIDが、本番のものになっているかを確かめる

5と6が大事です。一覧の「成功」だけで判断しないことが、この件の一番の学びでした。

まとめ

ワークフローから呼ぶDeluge関数は、関数のコードとルール側の「入力値の関連付け」の2か所で成り立っています。コードが正しくても、関連付けが空なら引数は null のままです。そして関数がエラーを自分で処理して終わると、実行結果は「成功」と表示されます。

関連付けが空になる条件は特定できていないため、関数を更新したら関連付けを毎回確かめること、関数の側で空の引数やAPIのエラーを知らせること。この2つを組み合わせるのが、当社がたどり着いた現実的な守り方です。

自動化が動かない原因は、関連付けのほかにもあります。承認プロセスとブループリントの実行順がぶつかる例は、Zoho CRMで承認プロセスが動かない原因は「ブループリント」だったで紹介しています。

Zoho CRMの関数やワークフローが思ったとおりに動かない、どこから調べればよいか分からないといった場合は、CRMサポートセンター(Zoho CRMカスタマイズ・設定代行サービス)までお気軽にご相談ください。

よくある質問

ワークフローの実行結果が「成功」なら、関数の処理は終わっていると考えてよいですか?

いいえ。一覧の「成功」は関数の呼び出しが終わったことを示すもので、業務の処理が終わったことは示しません。関数がエラーを拾って自分で終了した場合も「成功」と表示されます。関数の実行ログで入力値と処理内容を確かめてください。

関数のコードを更新すると、入力値の関連付けは必ず消えますか?

当社が確認した範囲では、必ず消えるわけではありません。コード更新の後に関連付けが空になっていたケースと、更新後も保持されていたケースの両方がありました。消える条件は特定できていないため、更新のたびに画面で確かめる運用をおすすめします。

関連付けが空になったルールは、どう直せばよいですか?

ワークフロールールの関数アクションを開き、入力値の欄で「#」を押してモジュールとID項目を選び直します。完了したら関数の設定を保存し、最後にワークフロールールを保存します。保存後にもう一度開いて、値が残っていることを確かめてください。

サンドボックスで作った関数を本番に移すときの注意点はありますか?

コードに書いたレコードIDに注意してください。当社の事例では、本番の関数にサンドボックス側のキャンペーンIDが残っており、APIがエラーを返していました。環境ごとにIDを切り替える仕組みを関数に入れておくと安全です。