はじめに
ケースの注文番号・追跡番号を入力規則で形をそろえたい。よくある要件です。ところが、規則を厳しくすると次の苦情が出ます。
- 「ord-12345678 と小文字で入れたら止められた」「追跡番号をハイフン付きで貼ったら止められた」
- 「倉庫のシステムからの連携が、入力規則で止まって取り込めない」
この記事では、配送の問い合わせのケースを例に、次の3つを組み合わせた形をまとめます。
- 保存前のフローで、小文字・ハイフン・空白を先に直す(入力規則より先に動く)
- 入力規則は、直したあとの形だけを見る
- カスタム権限を持つ連携のユーザーだけ、入力規則を通す
どれも「動くはず」「止まるはず」を先に書いてから Apex のテストで確かめ、24件すべて期待どおりでした。
対象読者
- 入力規則を作ったら、利用者や連携から「止められる」と言われている管理者
- 入力規則とフローのどちらで守るか迷っている方
検証の環境
Developer Edition で、Salesforce CLI の sf project deploy validate(組織を変えずに、反映とテストだけを試す)で確かめました。Claude Code を道具に使い、期待値の表を先に書いてから結果と突き合わせています。画面(編集画面でのエラーの見え方)は見ていません。
例にした依頼(架空)
配送の問い合わせをケースで受けています。入力がばらばらで集計に使えません。次を守らせてください。倉庫のシステムからの登録は止めないでください。
| # | 決まり | 作るもの |
|---|---|---|
| R1 | 配送の種類(遅延・破損・誤配)を選んだら、注文番号は ORD- + 数字8桁 |
入力規則 |
| R2 | 配送会社を選んだら、追跡番号は数字12桁(この依頼主の社内の決まり) | 入力規則 |
| R3〜R6 | 破損・誤配は配送会社が必須/補償額は破損・誤配だけ・5万円まで/破損は写真を受け取るまで閉じられない | 入力規則 |
| R7 | ゆれを直す: 追跡番号のハイフン・空白を消す、注文番号を大文字に | 保存前のフロー |
| R8 | 破損になったら、所有者に「写真を依頼」の ToDo | 保存後のフロー |
| R9 | 連携のユーザーは R1〜R6 で止めない | カスタム権限 + 権限セット |
1. 保存前のフローは、入力規則より先に動く
公式の「Triggers and Order of Execution」では、保存の順番は おおまかに 保存前のレコードトリガーフロー → before トリガー → (システムの検証と)カスタムの入力規則 です。つまり、保存前のフローで値を直せば、入力規則は直したあとの値を見ます。
フローの中身は「割り当て」1つと数式2つだけです。
<formulas>
<name>fOrder</name>
<dataType>String</dataType>
<expression>UPPER(TRIM({!$Record.Order_No__c}))</expression>
</formulas>
<formulas>
<name>fTracking</name>
<dataType>String</dataType>
<!-- ハイフン・半角空白・全角空白を消す -->
<expression>SUBSTITUTE(SUBSTITUTE(SUBSTITUTE({!$Record.Tracking_No__c}, "-", ""), " ", ""), " ", "")</expression>
</formulas>
...
<start>
<object>Case</object>
<recordTriggerType>CreateAndUpdate</recordTriggerType>
<triggerType>RecordBeforeSave</triggerType>
</start>
(割り当てで $Record.Order_No__c ← fOrder、$Record.Tracking_No__c ← fTracking。保存前のフローは $Record に入れるだけで保存され、DML は要りません)
確かめ方: フローを入れた状態と、フローだけを外した状態で同じテストを流しました。
| 入力 | フローあり | フローを外す |
|---|---|---|
遅延・ord-12345678
|
保存できた。保存値は ORD-12345678
|
注文番号の入力規則で止まった |
破損・ヤマト・1234-5678-9012
|
保存できた。保存値は 123456789012
|
追跡番号の入力規則で止まった |
ほかのテストは、フローの有無で結果が変わりませんでした。「フローが効いている」ことと「入力規則が効いている」ことを、別々に確かめられます。
2. 入力規則は「直したあとの形」だけを見る
AND(
NOT($Permission.Practice20_Bypass_VR),
NOT(ISPICKVAL(Ship_Issue_Type__c, "")),
NOT(REGEX(Order_No__c, "ORD-[0-9]{8}"))
)
- エラーの表示先(
errorDisplayField)に注文番号の項目を指定。Apex のSaveResult.getErrors()[0].getFields()にも項目の API 名が入りました -
REGEX は文字列全体で一致を見ました。
^・$を付けなくても、9桁(ORD-123456789)も、前に余計な文字(XORD-12345678)も止まりました - 空の項目も「一致しない」ので、「必須 + 形」が1つの規則で済みました
3. 連携のユーザーだけ通す: カスタム権限
入力規則の頭に NOT($Permission.<カスタム権限>) を付け、そのカスタム権限を入れた権限セットを連携のユーザーにだけ割り当てます。
<!-- customPermissions/Practice20_Bypass_VR.customPermission-meta.xml -->
<CustomPermission xmlns="http://soap.sforce.com/2006/04/metadata">
<isLicensed>false</isLicensed>
<label>入力規則を通す(連携用)</label>
</CustomPermission>
<!-- permissionsets/Practice20_Integration.permissionset-meta.xml -->
<PermissionSet xmlns="http://soap.sforce.com/2006/04/metadata">
<customPermissions>
<enabled>true</enabled>
<name>Practice20_Bypass_VR</name>
</customPermissions>
<label>Integration</label>
</PermissionSet>
プロファイル名やユーザー名で外すより、誰に外したかが権限セットの割り当てで一覧でき、外すのも割り当てを消すだけ なので、引き継いだ人が追えます。
確かめ方: テストの中でユーザーを作り、権限セットを割り当てて System.runAs で保存します。
| 入力 | 権限セットあり | 同じ人で権限セットなし |
|---|---|---|
| 遅延・注文番号なし | 保存できた | 注文番号の入力規則で止まった |
validate(反映前)の中でも、同じ反映に入れた権限セットをテストから照会して割り当てられました。
4. おまけ: 保存後のフロー(ToDo)の確かめどころ
-
「変わったときだけ」: 開始条件で「レコードが条件を満たすように更新された場合のみ」(
doesRequireRecordChangedToMeetCriteria=true)。遅延で作る → 0件、破損に変える → 1件、説明だけ直す → 1件のまま、を確かめました -
所有者がキューのとき: ToDo の割り当て先にキューは入れられないので、
LEFT({!$Record.OwnerId}, 3) = "005"(ユーザー)のときだけ作る分岐にしました。キューが所有者のケースもエラーなく保存できました - 200件まとめて: 破損のケースを200件一括で作り、ToDo 200件。上限に当たりませんでした
結果
| 件数 | |
|---|---|
| 保存できるはず | 12件 すべて保存できた |
| 止まるはず | 12件 すべて止まった(止まった文まで一致) |
| 保存前のフローを外す | 2件だけ落ちた(上の表) |
| 保存後のフローを外す | ToDo を見る3件だけ落ちた |
つまずき: 前からあるデータが「説明を直すだけ」で止まる
入力規則に ISNEW()・ISCHANGED() の絞りを付けていなかったため、規則を入れる前からある外れたケースは、関係ない項目を直すだけでも止まります。入れる前に次のどちらかを決めておくのが安全です。
- 新しいケースと、その項目を変えたときだけ見る:
AND(OR(ISNEW(), ISCHANGED(Order_No__c)), ...) - 先に古いデータを直す(保存前のフローで直せる形なら、一括で更新するだけで直る)
もう1つ、お客様の組織に前からある入力規則 も止めます。今回の組織には件名に「NG」を含むと止める古い規則があり、英大文字の件名 SHIPPING(「NG」を含む)が止まりました。新しい規則を足す前に、同じオブジェクトの既存の規則を一覧しておくと、原因の切り分けが速くなります。
確かめていないこと
- 編集画面で、エラーが項目の下に出るか・文の見え方(反映せず validate だけで確かめたため)
- 同じオブジェクトに保存前のフローが複数あるときの順番(公式では保証されない、とある。今回は1つだけ)
まとめ
- 形をそろえる要件は、保存前のフローで直す → 入力規則は直したあとを見る に分けると、利用者を止めすぎない
- 連携だけ通すのは
$Permission.<カスタム権限>+ 権限セット。誰に外したかが追える - テストは「フローを外すと、その分だけ落ちる」まで見ると、どれが効いているかが分かる
- 入れる前に、前からあるデータ(
ISNEW/ISCHANGED)と既存の入力規則を確かめる
筆者は Salesforce の設定の代行・相談を受けています(連絡先は Qiita のプロフィールに)。
参考
- Apex Developer Guide「Triggers and Order of Execution」 https://developer.salesforce.com/docs/atlas.en-us.apexcode.meta/apexcode/apex_triggers_order_of_execution.htm