🚨 The Problem with Case Milestones
If you’ve ever managed SLAs in Salesforce, you know how valuable milestones are. They track deadlines such as First Response or Case Resolution, helping teams deliver on time.
But here’s the catch:
Once a Case is closed, Salesforce doesn’t allow you to manually complete milestones anymore
https://help.salesforce.com/s/articleView?id=000393989&type=1
That creates a few headaches:
-
Agents might forget to close a milestone before resolving the Case.
-
The milestone stays “open” forever.
-
Reports suddenly show overdue or incomplete milestones, even if the customer issue was solved.
-
Managers begin asking: “Why are we missing so many milestones if cases are resolved?”
Sound familiar? I’ve been there too.
🤔 Why Does Salesforce Restrict This?
After digging into Salesforce docs, I realized this is intentional design.
The entitlement engine assumes that all milestone actions are finished before a Case closes. Once the Case is closed, Salesforce locks milestones to preserve SLA integrity.
In theory, this keeps data consistent. In practice, people forget. And when they do, your SLA reports look wrong.
âś… The Workaround: An Apex Trigger
To fix this, I wrote a small Apex Trigger that automatically completes open milestones the moment a Case is closed.
Here’s the code:
——————————————————————————————————–
-trigger CompleteMilestonesOnCaseClose on Case (after update) {
List<CaseMilestone> milestonesToUpdate = new List<CaseMilestone>();
for (Case c : Trigger.new) {
Case oldCase = Trigger.oldMap.get(c.Id);
// Only act if the case just got closed
if (!oldCase.IsClosed && c.IsClosed) {
List<CaseMilestone> openMilestones = [
SELECT Id, IsCompleted, CompletionDate
FROM CaseMilestone
WHERE CaseId = :c.Id AND IsCompleted = false
];
for (CaseMilestone cm : openMilestones) {
cm.CompletionDate = System.now();
milestonesToUpdate.add(cm);
}
}
}
if (!milestonesToUpdate.isEmpty()) {
update milestonesToUpdate;
}
}
———————————————————————————————-
🔍 How It Works
-
The trigger runs after a Case is updated.
-
It checks if the Case moved from Open → Closed.
-
It queries all open milestones linked to that Case.
-
It sets their CompletionDate = System.now().
-
Finally, it updates them in one go.
Simple, bulk-friendly, and reliable.
🚀 Why This Matters
With this quick automation in place:
-
Reports become more accurate.
-
Managers stop chasing “missed” milestones that never existed.
-
Your team spends less time fixing data and more time solving customer issues.
This small trigger has already saved my team from messy reports and unnecessary escalations.
đź’¬ Final Thoughts
Sometimes Salesforce’s design choices don’t align perfectly with how support teams work in real life. With just a few lines of Apex, you can bridge that gap and make reporting far more reliable.
👉 Have you faced similar entitlement or milestone issues? Drop your experience in the comments — I’d love to learn how others solved them too.
Informative