Working Patterns

From 3B Knowledge
Jump to navigation Jump to search

Generate recurring shifts for contacts from a reusable, rotating weekly template. Available in version 9.8+

End-User Guide

⚠️ The UI for this feature is delivered by the managed package and will change significantly once fully implemented. This describes the concept and the data, not the final screens.

What is a Working Pattern?

A Working Pattern is a repeating weekly schedule. Instead of creating shifts one at a time, you define the shape of someone's week once (which days they work and at what times), then generate all their shifts across a date range in one action.

Patterns can rotate over multiple weeks. A "2-week pattern" means Week A looks one way, Week B another, then it repeats. This handles things like "earlies one week, lates the next" or a 4-on/4-off rotation.

How it works

  1. A Working Pattern Type is the template — the rota itself (e.g. "Mon–Fri day shift" or "2-week rotating nights"). It is built once and reused for many people.
  2. A Working Pattern applies that template to one contact over a start and end date.
  3. Generating the pattern creates real Shifts, each pre-assigned to the contact and linked back to the pattern.

Things to know

  • One contact per pattern. Each Working Pattern belongs to a single contact.
  • Overnight shifts are automatic. If an end time is earlier than the start time (e.g. 22:00 → 06:00), the shift correctly rolls into the next day.
  • Rotation aligns to the calendar. Week 0 of the pattern starts on the Monday of the week containing your start date.
  • Generated shifts are normal shifts. Once created they behave like any other shift — they can be edited, reassigned, or checked for compliance.

The object structure

Working Pattern Type            (the template — built once, reused)
  └─ Working Pattern Day        (one row per working day, per week of the cycle)
        defines: week #, day of week, start time, end time

         ↓ applied to a contact over a date range

Working Pattern                 (the instance — one per contact)
  ├─ Contact
  ├─ Working Pattern Type        (which template)
  ├─ Start / End                 (the date range)
  ├─ Job
  └─ Shifts                      (everything generated, linked back here)

Admin Guide

Setup overview

  1. Create a Working Pattern Type (b3s__Working_Pattern_Type__c) — the template.
  2. Define its Working Pattern Days (b3s__Working_Pattern_Day__c) — one per working day per week of the rotation. (The workingPatternBuilder LWC provides a tabbed week/day editor for this.)
  3. Generate shifts by running the invocable — either via the bundled flow or from your own automation.

Objects & key fields

b3s__Working_Pattern_Type__c — the reusable template. Job/Site/Location set here are stamped onto every shift it generates.

Field Type Purpose
b3s__Work_Job__c Lookup (Job) Stamped onto generated shifts
b3s__Work_Site__c Lookup (Site) Stamped onto generated shifts
b3s__Work_Site_Location__c Lookup (Site Location) Stamped onto generated shifts

b3s__Working_Pattern_Day__c — one per working day, per week of the cycle.

Field Type Purpose
b3s__Working_Pattern_Type__c Master-Detail Parent template
b3s__Week_Number__c Number Week in the rotation, 0-based. Cycle length = max week + 1
b3s__Day_Number__c Number Weekday, Mon=0 … Sun=6
b3s__Start_Time__c Time Shift start
b3s__End_Time__c Time Shift end. If ≤ start, the shift is treated as overnight (ends next day)

b3s__Working_Pattern__c — the template applied to one contact.

Field Type Purpose
b3s__Contact__c Master-Detail The contact (one pattern per contact)
b3s__Working_Pattern_Type__c Lookup The template used
b3s__Start__c / b3s__End__c Date Generation date range
b3s__Job__c Lookup Defaults from the Type's Work_Job__c

b3s__Shift__c — generated output, linked back via b3s__Working_Pattern__c (Lookup, SetNull on delete).

The Invocable

Apex: WorkingPatternShiftService.generateFlow/Process label: Generate Working Pattern Shifts (category Workforce Management).

It validates and enqueues the work; the actual expansion runs async in WorkingPatternShiftJob (Queueable). This is deliberate — a year of shifts across many contacts would blow the synchronous DML limit. Contacts are processed 50 per job and chained automatically beyond that.

Inputs (Request):

Variable Type Required Notes
contactIds List<Id> One or many contacts
workingPatternTypeId Id The template to expand
startDate Date Range start (also anchors Week 0 to its Monday)
endDate Date Range end
workingPatternId Id Use an explicit existing pattern (honoured only for a single contact)
mode Integer 1 create (default), 2 regenerate, 3 delta

Modes:

  • 1 — Create: Creates a Working Pattern per contact (or uses the supplied one) and generates all shifts in the range.
  • 2 — Regenerate: Deletes the contact's existing shifts on the pattern, then recreates them. Use after editing the template.
  • 3 — Delta: Only inserts shifts that don't already exist. Use to extend the date range or backfill manually deleted gaps without touching existing shifts.

Bundled flow: Generate_Shifts_for_Working_Pattern is a screen flow launched from a Working Pattern record — it reads the record, asks for a mode, and calls the invocable. Use it as-is, clone it, or call the invocable from your own flows.

Adding more fields to generated shifts ⚠️

The invocable stamps a fixed set of seven fields onto every shift, and nothing else:

b3s__Contact__c              b3s__Work_Job__c
b3s__Working_Pattern__c      b3s__Work_Site__c
b3s__Scheduled_Start_Time__c b3s__Work_Site_Location__c
b3s__Scheduled_End_Time__c

It does not accept arbitrary field mappings, and we are not extending it to do so. If you need additional fields populated on generated shifts (record type, pay rate, status, custom flags, owner, etc.), add a before-save record-triggered flow on b3s__Shift__c.

This works cleanly because:

  • The shift already carries b3s__Working_Pattern__c at insert time, so your flow can look up the pattern, its Type, the Contact, and any related config to derive whatever it needs.
  • A before-save flow sets fields on the record in-flight with no extra DML — no governor-limit cost on top of the (already chunked, async) bulk insert.

To scope the flow to pattern-generated shifts only, gate it on b3s__Working_Pattern__c != null (or a more specific condition).

Notes & gotchas

  • Weekday indexing is Monday-based (Mon=0 … Sun=6) — not Salesforce's default Sunday-first. Match this when building Working Pattern Days.
  • Rotation is calendar-aligned. Week 0 / Day 0 is the Monday of the week containing startDate. Week index = (weeks since that Monday) mod (cycle length).
  • Times are wall-clock on the calendar date. Confirm time-zone behaviour matches your org's expectations before mass generation.
  • Delete behaviour: deleting a Working Pattern nulls the lookup on its shifts (SetNull) — it does not delete the shifts. Use Mode 2 to clear-and-recreate.
  • Generation uses Database.insert(list, false) (partial success) — a few bad rows won't roll back the whole batch. Check debug logs / job status if counts look off.