@salesforce/afv-skills 1.48.0 → 1.50.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +1 -1
- package/skills/education-cloud-multi-campus-configure/SKILL.md +0 -5
- package/skills/field-service-data-capture-form-deployer-configure/SKILL.md +180 -0
- package/skills/field-service-data-capture-form-deployer-configure/examples/inventory-transfer-spec.json +135 -0
- package/skills/field-service-data-capture-form-deployer-configure/examples/sample-spec.json +140 -0
- package/skills/field-service-data-capture-form-deployer-configure/examples/sectioned-spec.json +64 -0
- package/skills/field-service-data-capture-form-deployer-configure/references/field-types.md +297 -0
- package/skills/field-service-data-capture-form-deployer-configure/references/flow-metadata-json.md +243 -0
- package/skills/field-service-data-capture-form-deployer-configure/references/post-screen-automation.md +127 -0
- package/skills/field-service-data-capture-form-designer-configure/SKILL.md +110 -0
- package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-image.md +244 -0
- package/skills/field-service-data-capture-form-designer-configure/references/extraction-from-prompt.md +222 -0
- package/skills/field-service-data-capture-form-editor-configure/SKILL.md +134 -0
- package/skills/field-service-data-capture-reference-configure/SKILL.md +762 -0
- package/skills/field-service-data-capture-reference-configure/examples/DataCapture_Showcase.flow-meta.xml +2022 -0
- package/skills/field-service-data-capture-reference-configure/examples/Data_Capture_All_Components.flow-meta.xml +2170 -0
- package/skills/field-service-data-capture-reference-configure/examples/Repeater_with_prepopulation.flow-meta.xml +231 -0
- package/skills/field-service-foundation-setup-designer-get/SKILL.md +135 -0
- package/skills/field-service-mobile-branding-configure/SKILL.md +133 -0
- package/skills/field-service-mobile-branding-configure/examples/dark-blue-scheme.json +16 -0
- package/skills/field-service-mobile-branding-configure/examples/salesforce-default-scheme.json +16 -0
- package/skills/field-service-mobile-branding-configure/references/color-fields.md +66 -0
- package/skills/field-service-mobile-branding-configure/references/contrast-validation.md +55 -0
- package/skills/field-service-mobile-branding-configure/references/derivation-methodology.md +83 -0
- package/skills/field-service-objective-designer-configure/SKILL.md +342 -0
- package/skills/field-service-prework-brief-deployer-configure/SKILL.md +83 -0
- package/skills/field-service-scheduling-policy-designer-query/SKILL.md +121 -0
- package/skills/field-service-setup-orchestrator-get/SKILL.md +48 -0
- package/skills/field-service-sobject-create-configure/SKILL.md +56 -0
- package/skills/field-service-voice-to-form-configure/SKILL.md +650 -0
- package/skills/field-service-work-rule-designer-configure/SKILL.md +303 -0
|
@@ -0,0 +1,303 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: field-service-work-rule-designer-configure
|
|
3
|
+
description: "Designs the work rules for a Salesforce Field Service scheduling policy — the hard filters that determine which resources and time slots are eligible for an appointment. Step 2 of the three-part scheduling policy design flow; receives the policy block from sfs-scheduling-policy-designer and delegates to sfs-service-objective-designer when complete. Use this skill when a user wants to design or configure the work rules (hard eligibility filters) for a Field Service scheduling policy."
|
|
4
|
+
user-invocable: false
|
|
5
|
+
metadata:
|
|
6
|
+
version: "1.0"
|
|
7
|
+
domains: ["Field Service"]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Salesforce Field Service – Work Rule Designer
|
|
11
|
+
|
|
12
|
+
**Designs the work rules for a scheduling policy.** This skill collects the work rule configuration through a structured interview — one question at a time — and emits a `workRules[]` block as output. It does not create any Salesforce records. When complete, delegates to `sfs-service-objective-designer`.
|
|
13
|
+
|
|
14
|
+
**Interview phases:** Scheduling Policy → **Work Rules** (this skill) → Service Objectives → Record Creation
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Work Rules
|
|
19
|
+
|
|
20
|
+
**Work rules are hard filters.** They refine the candidate list for a service appointment by rejecting any service resource that violates a rule. They are always applied before service objectives, and objectives only ever score the resources that survive the rules. If a requirement is "must," it's a work rule; if it's "prefer," it's an objective.
|
|
21
|
+
|
|
22
|
+
### The 16 work rule types
|
|
23
|
+
|
|
24
|
+
Each row: **name — engine (DB/Apex) — what it does.** "DB w/ ESO" means the rule runs at the database level *only when Enhanced Scheduling and Optimization is enabled*, and as Apex otherwise. Include at least one DB rule to narrow to ~20 candidates before Apex rules run.
|
|
25
|
+
|
|
26
|
+
| Work Rule | Engine | What it does |
|
|
27
|
+
|---|---|---|
|
|
28
|
+
| **Service Resource Availability** | Apex — **MANDATORY** | Ensures a resource is actually available: respects operating hours, travel, breaks, absences, and existing assignments. Also enforces capacity for capacity-based resources. Configurable breaks, gaps, overtime, and travel-to/from-home. |
|
|
29
|
+
| **Match Time Rule** | Apex | Constrains the scheduling window from an appointment's date/time fields. Ships with standard rules **Earliest Start Permitted** and **Due Date** (both **mandatory**), plus Scheduled Start / Scheduled End (arrival-window based). |
|
|
30
|
+
| **Match Skills** | Apex | Matches an appointment's skill requirements to a resource's assigned skills; can enforce skill level. Skill Type Logic is **All Skills Match (AND)** (default) or **At Least One Skill Matches (OR)** (OR requires ESO). |
|
|
31
|
+
| **Match Fields** | DB w/ ESO | Matches one appointment field to one resource field (1:1). Use Extended Match instead when comparing one appointment field against multiple resource values. |
|
|
32
|
+
| **Match Boolean** | DB w/ ESO | Requires a checkbox field on the resource to be true (or false). **Max 5 per policy.** Ships with standard "Active Resources." |
|
|
33
|
+
| **Extended Match** | Database | Custom-criteria matching via a junction object linking an appointment field to a related list on the resource (e.g., serviceable postal codes, product lines). |
|
|
34
|
+
| **Match Territory** | Database | Restricts to resources who are primary or relocation members of the appointment's service territory. |
|
|
35
|
+
| **Working Territories** | Database | Enforces **primary and secondary** service territory memberships. |
|
|
36
|
+
| **Maximum Travel from Home** | Database | Caps distance/travel time between a resource's home base and any assigned appointment. |
|
|
37
|
+
| **Required Resources** | DB w/ ESO | Forces assignment to a resource marked **Required** (Resource Preference on the WO/WOLI). Very restrictive. |
|
|
38
|
+
| **Excluded Resources** | DB w/ ESO | Prevents assigning a resource marked **Excluded** on the WO/WOLI. |
|
|
39
|
+
| **Count Rule** | Apex | Caps assignments, hours, or a custom value per resource per day (e.g., ≤8 scheduled hours, ≤N items on a truck). Time Resolution is **Daily**. Up to 10 custom-field count rules per policy. |
|
|
40
|
+
| **Work Capacity** | Apex — **ESO only** | Enforces per-territory Work Capacity Limit records (e.g., cap install work at 80% of territory capacity). |
|
|
41
|
+
| **Service Appointment Visiting Hours** | Apex | Enforces customer operating hours / allowed visit windows (e.g., weekdays 8 AM–noon). All-or-nothing rule (no relevance groups). |
|
|
42
|
+
| **TimeSlot Designated Work** | Apex | Reserves a time slot/shift for a specific work type — only that type schedules in that window. All-or-nothing rule (no relevance groups). |
|
|
43
|
+
| **Service Crew Resources Availability** | Apex | Ensures a crew-type resource is only assigned when the crew meets the parent record's minimum crew size. |
|
|
44
|
+
|
|
45
|
+
### Interview order — MANDATORY
|
|
46
|
+
|
|
47
|
+
Walk through the 16 work rule types **in the exact order of the table in *The 16 work rule types* above** — top to bottom, one rule at a time. **Do NOT split the interview into a separate "which rules apply" pass and a later "configure them" pass, and do NOT reorder the rules.** For each rule, in order:
|
|
48
|
+
|
|
49
|
+
1. **Decide whether it applies.** Service Resource Availability is always in (no question). For every other rule, either the user's stated business needs already make it obviously needed, or ask the short **Applies when / ask** question in that rule's entry below. Interpret the user's needs against the *What it does* column — e.g. "resources need the right skills" → Match Skills; "cap travel from home" → Maximum Travel from Home.
|
|
50
|
+
2. **If it applies and it has configuration, ask that rule's config question(s) right now** — before moving on to the next rule. Never defer configuration to the end. If the rule is selection-only (no config), just confirm it and continue.
|
|
51
|
+
|
|
52
|
+
Then continue to the next rule in the table. Ask one question at a time. Only after you have walked all 16 rules is the rule list final.
|
|
53
|
+
|
|
54
|
+
**Do NOT ask a relevance-group / subset question on every rule.** Most rules apply policy-wide, and asking "all or a subset?" after each one is noise. Instead:
|
|
55
|
+
|
|
56
|
+
- **React to scoping the user volunteers.** If while answering a rule's question the user signals the rule is only for a specific scenario, workforce, or work type — e.g. "only for part-time techs," "just for installation jobs," "tighter cap in France" — *then* pursue it: confirm the basis (Service Territory Member for a resource subset, Service Appointment for a work subset), get the Boolean field name, and record `relevanceGroup: { basis, booleanField }` on that rule. (First check the rule supports that basis under ES&O — see *Relevance Groups*.)
|
|
57
|
+
- **Otherwise sweep for it once, at the end.** After all 16 rules are walked, ask a single closing question: *"Are there any constraints here that should apply only to a certain part of your workforce or to certain types of work — rather than to everyone/everything? For example, different break or travel limits for part-time vs. full-time techs, or stricter handling for a specific work type or region."* Only if the user says yes do you scope the affected rules (per the *Relevance Groups* section). If no, leave every `relevanceGroup` null.
|
|
58
|
+
|
|
59
|
+
Always include exactly one **Service Resource Availability** rule — the only mandatory rule this skill emits. Never emit Earliest Start Permitted or Due Date — provisioned automatically.
|
|
60
|
+
|
|
61
|
+
---
|
|
62
|
+
|
|
63
|
+
### The rules, in interview order
|
|
64
|
+
|
|
65
|
+
Take these in the order shown — it matches the table above. For each entry: **Applies when** tells you how to decide it's needed; **Ask** lists the config questions to ask *immediately* on a yes; **Emit** gives the exact `params` keys — use them verbatim so the data-layer skill can map them.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
69
|
+
**1. Service Resource Availability** *(always present — the only mandatory rule)*
|
|
70
|
+
Applies when: always. No applicability question.
|
|
71
|
+
Ask:
|
|
72
|
+
- "Can work run into **overtime**?" (yes/no)
|
|
73
|
+
- "Can resources **travel outside working hours** to/from home?" — if yes, ask how many minutes from home (to first job) and to home (from last job); "no limit" = 120; "no" = 0 for both
|
|
74
|
+
- Breaks interview (see *Interpreting and emitting break times* below)
|
|
75
|
+
|
|
76
|
+
Emit: `{ "enableOvertime": true|false, "travelFromHomeMinutes": <number>, "travelToHomeMinutes": <number>, "breaks": [ … ] }`
|
|
77
|
+
Note: Travel values are minutes — 0 = no travel outside working hours, 120 = effectively unlimited. If the user gives no availability detail, emit baseline (`enableOvertime: false`, travel keys and breaks omitted).
|
|
78
|
+
|
|
79
|
+
---
|
|
80
|
+
|
|
81
|
+
**2. Match Time Rule** *(arrival windows)*
|
|
82
|
+
Applies when: appointments should honor customer **arrival windows** / required arrival times. Ask: "Should appointments honor customer arrival windows?"
|
|
83
|
+
Emit: on a yes, emit the **two** default rules from the *Arrival Window Match Time rules* table below — do not ask the user to fill these in.
|
|
84
|
+
|
|
85
|
+
---
|
|
86
|
+
|
|
87
|
+
**3. Match Skills**
|
|
88
|
+
Applies when: resources need specific skills / proficiency levels.
|
|
89
|
+
Ask: "Should the resource also **meet a minimum skill level** (proficiency), or is simply *having* the skill enough?"
|
|
90
|
+
Emit: `{ "matchSkillLevel": true|false }`
|
|
91
|
+
Note: Do not ask about skill-type AND/OR logic — this skill does not configure `skillTypeLogic`.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
**4. Match Fields**
|
|
96
|
+
Applies when: one appointment field must match one resource field (1:1). (For one appointment field vs. multiple resource values, use Extended Match instead.)
|
|
97
|
+
Ask: "Which Service Appointment field must match which Service Resource field, and with what operator?"
|
|
98
|
+
Emit: `{ "serviceProperty": "<SA field>", "resourceProperty": "<resource field>", "booleanOperator": "=" }`
|
|
99
|
+
Note: Operator is one of `=`, `>=`, `<=`, `>`, `<` (default `=`). Field names are the customer's own — pass through as given.
|
|
100
|
+
|
|
101
|
+
---
|
|
102
|
+
|
|
103
|
+
**5. Match Boolean**
|
|
104
|
+
Applies when: a checkbox on the resource must be true/false — including non-skill matching factors (e.g., serviceable postal codes).
|
|
105
|
+
Ask: "Which checkbox field on the resource must be true (or false)?"
|
|
106
|
+
Emit: `{ "resourceProperty": "<resource field>", "value": true|false }`
|
|
107
|
+
Note: Max 5 Match Boolean rules per policy.
|
|
108
|
+
|
|
109
|
+
---
|
|
110
|
+
|
|
111
|
+
**6. Extended Match** *(advisory only — data-layer skill will not build this)*
|
|
112
|
+
Applies when: custom-criteria matching via a junction object (e.g., serviceable postal codes, product lines).
|
|
113
|
+
Ask: None — no params to collect. Advise the user to set up before deploying:
|
|
114
|
+
1. A junction object with exactly **two** Master-Detail relationships (to Service Resource + matched object) — packaged trigger requires exactly two or the rule fails
|
|
115
|
+
2. A Service Appointment Lookup field driving the match; a reference field on the junction matched against it
|
|
116
|
+
3. Once those exist, create and configure the rule manually in Setup (Field Service Settings → Scheduling → Work Rules)
|
|
117
|
+
|
|
118
|
+
Capture intended objects/fields in `prerequisites` as advisory text — do not emit in `workRules[]`.
|
|
119
|
+
|
|
120
|
+
---
|
|
121
|
+
|
|
122
|
+
**7. Match Territory** — *(skip entirely; not part of the interview)*
|
|
123
|
+
This interview never emits a standalone Match Territory rule. **Skip it silently** — do not ask a Match Territory question, and do not announce or narrate that you are skipping it. Move straight from rule 6 to rule 8 with no mention of Match Territory at all. (If a user explicitly asks for primary/relocation-only territory scoping, advise manual configuration then — but never raise it yourself. Also: don't cover a resource by both Match Territory and Working Territories.)
|
|
124
|
+
|
|
125
|
+
---
|
|
126
|
+
|
|
127
|
+
**8. Working Territories**
|
|
128
|
+
Applies when: work must be restricted to the resource's **primary and secondary** service territory memberships.
|
|
129
|
+
Ask: None — selecting the rule is sufficient.
|
|
130
|
+
Emit: `{ "workingLocationEnablePrimary": true }`
|
|
131
|
+
|
|
132
|
+
---
|
|
133
|
+
|
|
134
|
+
**9. Maximum Travel from Home**
|
|
135
|
+
Applies when: capping distance/travel time between a resource's home and any assigned appointment / controlling travel cost across large territories.
|
|
136
|
+
Ask: "Is the cap by **distance** or by **travel time**?" (see the cap-type note below), plus the cap value.
|
|
137
|
+
Emit: `{ "maxTravelFromHome": <number>, "maxTravelFromHomeType": "Distance"|"Travel Time" }`
|
|
138
|
+
Note: Distance unit (miles vs km) is not part of the rule — governed by org locale. For Travel Time, value is minutes.
|
|
139
|
+
|
|
140
|
+
---
|
|
141
|
+
|
|
142
|
+
**10. Required Resources** *(selection-only)*
|
|
143
|
+
Applies when: any work order ever has a resource marked **Required** that must always be assigned. Ask: "Do any work orders ever have a specific resource marked *Required* that must always be assigned to that job?"
|
|
144
|
+
Emit: `{}`
|
|
145
|
+
Prerequisite: Resource Preference records must exist on the work order / WOLI — the rule enforces them but does not create them.
|
|
146
|
+
|
|
147
|
+
---
|
|
148
|
+
|
|
149
|
+
**11. Excluded Resources** *(selection-only)*
|
|
150
|
+
Applies when: any work order ever has a resource marked **Excluded** that must never be assigned. Ask: "Do any work orders ever have a resource marked *Excluded* that must never be assigned?"
|
|
151
|
+
Emit: `{}`
|
|
152
|
+
Prerequisite: Resource Preference records must exist on the work order / WOLI — the rule enforces them but does not create them.
|
|
153
|
+
|
|
154
|
+
---
|
|
155
|
+
|
|
156
|
+
**12. Count Rule**
|
|
157
|
+
Applies when: capping the number/duration of appointments (or a custom value) per resource per day.
|
|
158
|
+
Ask: Have the user describe the limit in plain terms, then classify into:
|
|
159
|
+
- `countBy` — `"Appointments"` (count of jobs), `"Hours"` (duration cap), or `"Custom"` (sum of a custom SA field)
|
|
160
|
+
- `maxValue` — the numeric cap (for Hours, convert to hours)
|
|
161
|
+
- `fieldHint` — the SA field to sum; `null` for a plain Appointments count
|
|
162
|
+
|
|
163
|
+
Emit: `{ "countBy": "Appointments"|"Hours"|"Custom", "maxValue": <number>, "fieldHint": "<SA field>"|null }`
|
|
164
|
+
Note: Time Resolution is always Daily; counted object is always Service Appointment — data-layer skill sets both automatically. Up to 10 custom-field count rules per policy. When countBy is Custom or Hours against a field, add prerequisite: "Confirm field `<fieldHint>` exists on Service Appointment."
|
|
165
|
+
|
|
166
|
+
---
|
|
167
|
+
|
|
168
|
+
**13. Work Capacity** *(ESO only — selection-only)*
|
|
169
|
+
Applies when: Work Capacity Limit records cap how much work schedules per territory. Ask: "Do you use Work Capacity Limit records to cap how much work can be scheduled per territory?"
|
|
170
|
+
Emit: `{}`
|
|
171
|
+
Prerequisite: WorkCapacityLimit records must be configured per territory outside the policy.
|
|
172
|
+
|
|
173
|
+
---
|
|
174
|
+
|
|
175
|
+
**14. Service Appointment Visiting Hours** *(selection-only)*
|
|
176
|
+
Applies when: customers have allowed visit windows that should block scheduling outside those hours. Ask: "Do customers have allowed visit windows (e.g., weekdays only, or mornings only) that should block scheduling outside those hours?"
|
|
177
|
+
Emit: `{}`
|
|
178
|
+
Note: Do not ask for the windows — they are per-account data on OperatingHours records, not a policy-wide value. All-or-nothing rule — no relevance-group scoping.
|
|
179
|
+
Prerequisite: Each account must have visiting/operating hours populated; the Work Order's Visiting Hours must resolve from the account.
|
|
180
|
+
|
|
181
|
+
---
|
|
182
|
+
|
|
183
|
+
**15. TimeSlot Designated Work** *(selection-only)*
|
|
184
|
+
Applies when: certain time slots must be reserved for specific types of work. Ask: "Do you need to reserve certain time slots for specific types of work (e.g., install work only in morning slots)?"
|
|
185
|
+
Emit: `{}`
|
|
186
|
+
Note: Do not ask for slot→work mappings — that is data setup. Phrase the selection as "types of work," not "Work Type" (the designation is broader than the Work Type object). All-or-nothing rule — no relevance-group scoping.
|
|
187
|
+
Prerequisite: Time slots must be configured to designate the intended work.
|
|
188
|
+
|
|
189
|
+
---
|
|
190
|
+
|
|
191
|
+
**16. Service Crew Resources Availability**
|
|
192
|
+
Applies when: crew-type resources must only be assigned when the crew meets the parent record's minimum crew size.
|
|
193
|
+
Ask:
|
|
194
|
+
- "Should the rule evaluate individual crew members' availability and skills, not just the crew record?" → `considerCrewMembership`
|
|
195
|
+
- "What is the maximum number of extra resources beyond the base crew that can be pulled in?" → `maxAdditionalResources` (optional)
|
|
196
|
+
|
|
197
|
+
Emit: `{ "considerCrewMembership": true|false, "maxAdditionalResources": <number> }` (omit `maxAdditionalResources` if blank)
|
|
198
|
+
|
|
199
|
+
---
|
|
200
|
+
|
|
201
|
+
### Configuration reference notes
|
|
202
|
+
|
|
203
|
+
These deep-dives support the **Ask** lines above; consult them when configuring the rule that references them.
|
|
204
|
+
|
|
205
|
+
**Arrival Window Match Time rules (default pair — rule 2).** When the user confirms appointments should honor customer arrival windows, emit **two** Match Time rules with these exact default settings — do not ask the user to fill these in, they are the standard arrival-window configuration:
|
|
206
|
+
|
|
207
|
+
| Setting | Rule A | Rule B |
|
|
208
|
+
|---|---|---|
|
|
209
|
+
| Name | `Arrival Window Start` | `Arrival Window End` |
|
|
210
|
+
| Service Schedule Time Property | `SchedStartTime` | `SchedStartTime` |
|
|
211
|
+
| Service Time Operator | `Later than or Equal to` | `Before or Equal to` |
|
|
212
|
+
| Service Time Property | `ArrivalWindowStartTime` | `ArrivalWindowEndTime` |
|
|
213
|
+
| Pass Empty Values | `true` | `true` |
|
|
214
|
+
|
|
215
|
+
Emit each as a Match Time work rule whose `params` carry those four values (keys `serviceScheduleTimeProperty`, `serviceTimeOperator`, `serviceTimeProperty`, `passEmptyValues`). These are separate from the mandatory Earliest Start Permitted / Due Date rules (never emitted).
|
|
216
|
+
|
|
217
|
+
**Interpreting and emitting break times — clock time vs. shift-start offset (rule 1).** A Service Resource Availability rule expresses breaks in one of two shapes, and **this skill decides the shape and emits the values the data-layer skill needs** — the data-layer skill never receives a clock time it has to convert. Choose the shape as follows:
|
|
218
|
+
|
|
219
|
+
- **One fixed daily break at an absolute clock time** (e.g. "30 minutes at 12:00 every day") → emit it as an **absolute** break: `{ "mode": "absolute", "startClock": "12:00", "durationMinutes": 30 }`. No offset math, no working-day start needed.
|
|
220
|
+
- **One or more breaks defined as an offset from the start of the working day** (e.g. "a 30-minute lunch starting 3 hours into the shift") → emit each as an **offset** break, in **minutes from the start of the working day**: `{ "mode": "offset", "earliestStartOffsetMinutes": 180, "latestEndOffsetMinutes": 240, "durationMinutes": 30 }`. All three of `earliestStartOffsetMinutes`, `latestEndOffsetMinutes`, and `durationMinutes` are **mandatory** for an offset break. **When the user states the break in offset terms already** (e.g. "3 hours after the start of day"), that offset *is* `earliestStartOffsetMinutes` (180) — **do not ask for the working-day start; you don't need it.**
|
|
221
|
+
- **Breaks given as clock times but there is more than one** (e.g. "15 minutes at 10:00 and 30 minutes at 12:00") → you must use the **offset** shape, which means **converting each clock time into an offset from the start of the working day**. You cannot do that without knowing when the day starts, so **ask the user for the shift / working-day start**, then compute `earliestStartOffsetMinutes = (break start clock − day start)` in minutes for each break. Never assume the day starts at midnight (that would turn "10:00" into a wrong 600-minute offset). *(Only ask for the day start in this clock-time case — never when the break is already expressed as an offset.)*
|
|
222
|
+
|
|
223
|
+
**Always emit `latestEndOffsetMinutes` for every offset break — ask for it directly, do not fabricate a window.** The earliest start comes from what the user stated (an offset, or a converted clock time) — **do not invent ± tolerance windows around it** (no "±1 hour" / "±2 hour" options). If the user only gave a break start (or a duration with no stated finish-by), **ask them plainly for the latest the break may end**, phrased in the *same terms they used*: if they gave an offset ("starts 3 hours after start of day"), ask "what is the latest it may end, as time after the start of the day?" and convert (e.g. "4 hours after start" → 240); if they gave a clock time, ask for a clock time and convert with the day start. If the user says the break is fixed/pinned with no flex, set `latestEndOffsetMinutes = earliestStartOffsetMinutes + durationMinutes`. Never emit an offset break missing any of the three fields, and never guess the latest-end. If a break requirement is too involved to convert reliably, ask clarifying questions or recommend the manual approach rather than guessing.
|
|
224
|
+
|
|
225
|
+
**Maximum Travel from Home — establish the cap type, not the unit (rule 9).** When a requirement caps how far a resource may travel from home, **ask the user whether the cap is by distance or by travel time** — the two are configured differently and the data-layer skill needs to know which. Emit the value and the type in `params`: `{ "maxTravelFromHome": 50, "maxTravelFromHomeType": "Distance" | "Travel Time" }`. Interpret the user's phrasing to set the *type* — "50 miles"/"50 km" ⇒ `Distance`, "45 minutes" ⇒ `Travel Time` — but **do not ask for or emit a distance unit (miles vs km): it is not part of the work-rule config**; the unit is governed by the org's locale/distance settings elsewhere, so the rule stores only the number. For `Travel Time` the value is minutes. Never emit the cap value without its type.
|
|
226
|
+
|
|
227
|
+
---
|
|
228
|
+
|
|
229
|
+
## Relevance Groups
|
|
230
|
+
|
|
231
|
+
A relevance group scopes a single work rule or service objective so it applies only to certain appointments or resources, instead of the whole policy. This lets one policy hold different logic for different work or resource types — e.g., different break/travel limits for part-time vs. full-time employees, or expedited scheduling for high-value accounts.
|
|
232
|
+
|
|
233
|
+
### How it works, and the division of labor
|
|
234
|
+
|
|
235
|
+
A relevance group is driven by a Boolean (true/false) field. Every standard or custom Boolean field on the Service Appointment and Service Territory Member objects is selectable in the rule/objective's Relevance Group dropdown. On a work rule or objective, you pick the limiting Boolean field; the rule/objective then applies only to records where that field is true. The two bases are just the two objects the Boolean can live on:
|
|
236
|
+
|
|
237
|
+
- **Service Appointment basis** — scopes by the appointment being evaluated (e.g., a formula checkbox "Platinum Account" that's true when the related account tier is Platinum). Use to target appointment types.
|
|
238
|
+
- **Service Territory Member basis** — scopes by the service territory member of the resource being evaluated (e.g., "Part-Time" / "Full-Time" checkboxes). Use to target resource populations. Only primary and relocation memberships are supported — not secondary.
|
|
239
|
+
|
|
240
|
+
In the design: decide the basis (Service Appointment vs. Service Territory Member) and the name of the Boolean field that identifies the subset, then record both on the rule/objective in the build spec (`relevanceGroup: { basis, booleanField }`). This skill only decides which field scopes which rule/objective — wiring the group onto the record is the data-layer skill's concern.
|
|
241
|
+
|
|
242
|
+
The Boolean field itself is a prerequisite the user must own, not something either skill in this pair creates: creating the field is a schema change (DDL), and setting its true/false values on records needs a flow, formula, trigger, or data load. So advise the user to, before deploying: (1) create one custom Boolean field on the appropriate object (Service Territory Member for a resource subset, Service Appointment for a work subset) per subset; (2) populate it true for exactly the records in that subset (via flow/formula/import), keeping subsets mutually exclusive where the rule type requires it. Then reference that field by name in the build spec so the data-layer skill can attach it as the relevance group.
|
|
243
|
+
|
|
244
|
+
### Worked example (the canonical pattern)
|
|
245
|
+
|
|
246
|
+
To apply a Match Boolean rule (or any scoping) to only certain appointment types: identify (or have the user create) a Boolean field on the Service Appointment that is true for those appointments, and name it as the rule's relevance group in the build spec. The rule then applies only to appointments where the field is true. The same pattern with a Service Territory Member Boolean (e.g., Part-Time vs. Full-Time) lets you design two copies of the Maximum Travel from Home rule with different limits — one scoped to part-timers, one to full-timers.
|
|
247
|
+
|
|
248
|
+
For objectives, the classic example is combining ASAP with a relevance group: a formula checkbox "Platinum Account" on the appointment, an ASAP objective named "Expedite Platinum Accounts" scoped to it with a high weight, so platinum jobs schedule sooner (accepting more travel). Give scoped high-priority objectives a clearly higher weight, or the engine may prefer not to schedule the appointment at all because of its ASAP penalty.
|
|
249
|
+
|
|
250
|
+
### Scoping any rule or objective to a subset (the general rule)
|
|
251
|
+
|
|
252
|
+
This applies to every work rule and every service objective — not just breaks or availability. Whenever a request says a rule or objective should apply to only certain resources or only certain work, rather than the whole policy, the mechanism is a relevance group. Watch for this signal and reach for it every time:
|
|
253
|
+
|
|
254
|
+
- "…applies to certain types of resources" (e.g. "resources in France", "part-time techs", "senior engineers", "the install crew") → create a Service Territory Member relevance group: a Boolean field on Service Territory Member that is true for exactly those resources, selected as the rule/objective's relevance group.
|
|
255
|
+
- "…applies to certain types of work" (e.g. "installation jobs", "platinum-account appointments", "emergency work orders", "jobs over 2 hours") → create a Service Appointment relevance group: a Boolean field on Service Appointment that is true for exactly those appointments, selected as the rule/objective's relevance group.
|
|
256
|
+
|
|
257
|
+
Always check whether the specific rule/objective supports the basis you need. Not every rule/objective can be scoped by Service Territory Member, and not every one can be scoped by Service Appointment. Before recommending a relevance group, verify the relevance-group support matrix for that exact rule or objective — consider only Enhanced Scheduling & Optimization (ES&O) support and ignore the legacy/non-Enhanced columns. If the needed basis isn't supported for that rule/objective under ES&O, say so and suggest the closest supported alternative instead of inventing one.
|
|
258
|
+
|
|
259
|
+
When two subsets each need a different configuration of the same rule/objective, design one instance per subset — never one merged instance. A single rule/objective instance applies to every record it covers, so you cannot express "France gets pattern A, everyone else gets pattern B" in one instance. Instead specify one instance per subset, each scoped by its own distinct Boolean field, and keep the groups mutually exclusive (for single-coverage rule types like Service Resource Availability, an overlap throws an error — see *Key rules and gotchas*). Example: "Resources in France get a 15-minute break at 10 AM and a lunch between 12 and 2; all other resources get a 30-minute break between 12 and 3" needs two Service Resource Availability rules — "Availability – France" scoped to a `Break_Group_France__c` STM checkbox, "Availability – Standard" scoped to a `Break_Group_Standard__c` STM checkbox — each carrying only its own group's breaks, with every resource landing in exactly one group.
|
|
260
|
+
|
|
261
|
+
When the scenario is genuinely too complex, recommend a manual design. If a request combines multiple subsets, ambiguous values, and relevance-group fields that don't exist yet, don't force a single merged instance into the spec. Walk the user through the relevance-group design above and let them refine it (or spec only the parts that are unambiguous), rather than emitting a plausible-looking but wrong merged rule/objective. Prefer asking clarifying questions (which subset? resources or work? what Boolean field identifies each? is that basis supported for this rule/objective under ES&O?) over guessing.
|
|
262
|
+
|
|
263
|
+
### Key rules and gotchas
|
|
264
|
+
|
|
265
|
+
- **Relevance groups must be mutually exclusive.** If two rules with relevance groups overlap, the more restrictive one wins — and for Service Resource Availability, an overlap throws an error. Each resource must be covered by exactly one Service Resource Availability rule.
|
|
266
|
+
- **Additive rule types** — can appear multiple times and legitimately cover the same resources/appointments: Count Rule, Extended Match, Match Boolean, Match Fields, Match Time.
|
|
267
|
+
- **Single-coverage rule types** — a resource/appointment must be covered by at most one instance at a time: Match Skills, Match Territory, Maximum Travel from Home, Required Resources, Service Crew Resource Availability, Service Resource Availability, Working Territories. (Also: don't cover a resource by both Match Territory and Working Territories at once.)
|
|
268
|
+
- **All-or-nothing rules — no relevance groups:** TimeSlot Designated Work and Service Appointment Visiting Hours. Also Work Capacity doesn't support relevance groups.
|
|
269
|
+
- **Objectives** can be repeated with relevance groups too, but a record must not meet the criteria for two objectives of the same type at once — except Resource Priority, which can legitimately apply twice to the same appointments if each instance points to a different resource priority field (e.g., "Primary Priority" and "Secondary Priority"/"Tenure").
|
|
270
|
+
- Support for whether a rule/objective can be scoped by appointment vs. territory member differs between the Enhanced and non-Enhanced engines — verify the support tables when scoping. Group Nearby and Same Site objectives do not support relevance groups at all.
|
|
271
|
+
|
|
272
|
+
---
|
|
273
|
+
|
|
274
|
+
## Output
|
|
275
|
+
|
|
276
|
+
Once all rules are confirmed, emit the `workRules[]` block and show a plain-English summary — rule name, what it filters, any key parameters. Ask the user to confirm before delegating.
|
|
277
|
+
|
|
278
|
+
The `workRules[]` block carried forward to the next step:
|
|
279
|
+
|
|
280
|
+
```json
|
|
281
|
+
{
|
|
282
|
+
"workRules": [
|
|
283
|
+
{
|
|
284
|
+
"type": "<rule type>",
|
|
285
|
+
"name": "<policy name> - <rule label>",
|
|
286
|
+
"mandatory": true | false,
|
|
287
|
+
"params": { ... },
|
|
288
|
+
"relevanceGroup": { "basis": "ServiceAppointment" | "ServiceTerritoryMember", "booleanField": "<field API name>" } | null
|
|
289
|
+
}
|
|
290
|
+
],
|
|
291
|
+
"prerequisites": [ "<advisory text for items the user must set up manually>" ]
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
---
|
|
296
|
+
|
|
297
|
+
## Handoff
|
|
298
|
+
|
|
299
|
+
When the user confirms the work rules, delegate to `sfs-service-objective-designer`. Pass both the `policy` block and the `workRules[]` block as context — the objective designer uses the selected rules to contextually surface relevant objectives (e.g., Match Skills selected → suggest Skill Level and Skill Preference objectives).
|
|
300
|
+
|
|
301
|
+
Do not start the service objective interview here. Transition message:
|
|
302
|
+
|
|
303
|
+
> "Work rules are locked in. Next: service objectives — the scoring criteria that rank the eligible candidates. I'll walk through the trade-off questions one at a time."
|