0% found this document useful (0 votes)
42 views22 pages

Salesforce Trigger Scenario Based Questions

The document outlines various trigger scenarios in Salesforce, including the creation of forecast records for high-value opportunities, automatic delivery record creation for activated orders, escalation of unassigned high-priority tasks, and updates to related cases when assets are modified. Each scenario includes a trigger, handler, and test class to ensure proper functionality and bulk-safe operations. The document emphasizes recursive protection and logging changes for auditing purposes.

Uploaded by

aksfdcnotes
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
42 views22 pages

Salesforce Trigger Scenario Based Questions

The document outlines various trigger scenarios in Salesforce, including the creation of forecast records for high-value opportunities, automatic delivery record creation for activated orders, escalation of unassigned high-priority tasks, and updates to related cases when assets are modified. Each scenario includes a trigger, handler, and test class to ensure proper functionality and bulk-safe operations. The document emphasizes recursive protection and logging changes for auditing purposes.

Uploaded by

aksfdcnotes
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 22

Trigger Scenario: Opportunity Trigger: Auto Forecast Creation & Async

Notification

Problem Statement:
When an Opportunity with Amount > $500,000 is inserted, create a Forecast__c record with the Opportunity's
expected revenue and quarter. Additionally, notify the Account Owner via Chatter using a Queueable. Ensure
recursive protection is in place.

Trigger:
trigger OpportunityTrigger on Opportunity (after insert) {
switch on [Link] {
when AFTER_INSERT {
if (![Link]()) {
[Link]();
[Link]([Link]);
}
}
}
}

Trigger Handler:
public class OpportunityTriggerHandler {
public static void handleAfterInsert(List<Opportunity> opportunities) {
List<Forecast__c> forecasts = new List<Forecast__c>();
Set<Id> accountIds = new Set<Id>();

for (Opportunity opp : opportunities) {


if ([Link] > 500000) {
[Link](new Forecast__c(
Opportunity__c = [Link],
Forecast_Amount__c = [Link],
Forecast_Quarter__c = 'Q' + [Link]([Link]([Link]() / 3.0))
));
if ([Link] != null) {
[Link]([Link]);
}
}
}

if (![Link]()) insert forecasts;

if (![Link]()) {
[Link](new NotifyAccountOwnersQueueable(accountIds));
}
}
}

public class NotifyAccountOwnersQueueable implements Queueable {


private Set<Id> accountIds;
public NotifyAccountOwnersQueueable(Set<Id> accountIds) {
[Link] = accountIds;
}

public void execute(QueueableContext context) {


List<Account> accounts = [SELECT Id, OwnerId FROM Account WHERE Id IN :accountIds];
List<FeedItem> posts = new List<FeedItem>();

for (Account acc : accounts) {


[Link](new FeedItem(
ParentId = [Link],
Body = 'A high-value Opportunity forecast has been created.',
Type = 'TextPost'
));
}
if (![Link]()) insert posts;
}
}

Test Class:
@isTest
private class OpportunityTriggerHandlerTest {
@isTest static void testHighValueForecastAndNotify() {
Account acc = new Account(Name='Test Account');
insert acc;

Opportunity opp = new Opportunity(Name='Big Deal', StageName='Prospecting',


CloseDate=[Link]().addMonths(1), Amount=600000, AccountId=[Link]);
insert opp;

List<Forecast__c> forecasts = [SELECT Id FROM Forecast__c WHERE Opportunity__c = :[Link]];


[Link](1, [Link]());

[Link]();
[Link](new NotifyAccountOwnersQueueable(new Set<Id>{[Link]}));
[Link]();

List<FeedItem> posts = [SELECT Id FROM FeedItem WHERE Body LIKE '%high-value%'];


[Link]([Link]() > 0);
}
}
Trigger Scenario: Order Trigger: Auto-Creation of Delivery__c Record
After Insert

Problem Statement:
When an Order is inserted with a Status of 'Activated', automatically create a Delivery__c record. Link the
Delivery__c to the Order via a lookup and set a default Estimated_Delivery_Date__c. Ensure the logic is
bulk-safe.

Trigger:
trigger OrderTrigger on Order (after insert) {
switch on [Link] {
when AFTER_INSERT {
[Link]([Link]);
}
}
}

Trigger Handler:
public class OrderTriggerHandler {
public static void handleAfterInsert(List<Order> orders) {
List<Delivery__c> deliveries = new List<Delivery__c>();

for (Order o : orders) {


if ([Link] == 'Activated') {
[Link](new Delivery__c(
Order__c = [Link],
Estimated_Delivery_Date__c = [Link]().addDays(7),
Status__c = 'Scheduled'
));
}
}

if (![Link]()) {
insert deliveries;
}
}
}

Test Class:
@isTest
private class OrderTriggerHandlerTest {
@isTest static void testDeliveryCreationOnOrderInsert() {
Account acc = new Account(Name='Test Account');
insert acc;

Order ord = new Order(Name='Test Order', Status='Activated', AccountId=[Link], EffectiveDate=Syst


insert ord;

List<Delivery__c> deliveries = [SELECT Id, Order__c FROM Delivery__c WHERE Order__c = :[Link]];
[Link](1, [Link]());
}
}
Trigger Scenario: Task Trigger: Escalate Unassigned High-Priority
Tasks

Problem Statement:
When a Task is inserted with Priority 'High' and no OwnerId, assign it to a default queue and log escalation in
Task_Log__c. Ensure the logic is bulk-safe and done in before insert.

Trigger:
trigger TaskTrigger on Task (before insert) {
switch on [Link] {
when BEFORE_INSERT {
[Link]([Link]);
}
}
}

Trigger Handler:
public class TaskTriggerHandler {
public static void handleBeforeInsert(List<Task> tasks) {
Id defaultQueueId = [SELECT Id FROM Group WHERE Name = 'Default Escalation Queue' AND Type = 'Que
List<Task_Log__c> logs = new List<Task_Log__c>();

for (Task t : tasks) {


if ([Link] == 'High' && [Link] == null) {
[Link] = defaultQueueId;
[Link](new Task_Log__c(
Task_Subject__c = [Link],
Escalation_Reason__c = 'High priority task with no owner',
Escalated_To__c = defaultQueueId
));
}
}

if (![Link]()) {
insert logs;
}
}
}

Test Class:
@isTest
private class TaskTriggerHandlerTest {
@isTest static void testEscalationForUnassignedTask() {
Task t = new Task(Subject='Critical Follow-up', Priority='High');
insert t;

Task inserted = [SELECT Id, OwnerId FROM Task WHERE Id = :[Link]];


[Link](null, [Link]);

List<Task_Log__c> logs = [SELECT Id FROM Task_Log__c WHERE Task_Subject__c = 'Critical Follow-up'


[Link](1, [Link]());
}
}
Trigger Scenario: Asset Trigger: Update Related Case with Asset
Summary

Problem Statement:
When an Asset is updated and linked to a Case via Related_Case__c, update the Case's
Asset_Summary__c field with the Asset Name + SerialNumber. Ensure bulk-safe and efficient lookup and
update.

Trigger:
trigger AssetTrigger on Asset (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link]);
}
}
}

Trigger Handler:
public class AssetTriggerHandler {
public static void handleAfterUpdate(List<Asset> assets) {
Map<Id, String> caseUpdates = new Map<Id, String>();

for (Asset a : assets) {


if (a.Related_Case__c != null) {
String summary = [Link] + ' (' + [Link] + ')';
[Link](a.Related_Case__c, summary);
}
}

List<Case> casesToUpdate = new List<Case>();


for (Id caseId : [Link]()) {
[Link](new Case(
Id = caseId,
Asset_Summary__c = [Link](caseId)
));
}

if (![Link]()) {
update casesToUpdate;
}
}
}

Test Class:
@isTest
private class AssetTriggerHandlerTest {
@isTest static void testCaseUpdateFromAsset() {
Case c = new Case(Subject='Test Case');
insert c;

Asset a = new Asset(Name='Device A', SerialNumber='12345', Related_Case__c=[Link]);


insert a;

[Link] = '67890';
update a;

Case updated = [SELECT Asset_Summary__c FROM Case WHERE Id = :[Link]];


[Link](updated.Asset_Summary__c.contains('Device A'));
[Link](updated.Asset_Summary__c.contains('67890'));
}
}
Trigger Scenario: Event Trigger: Audit Reschedule into
Calendar_Audit__c

Problem Statement:
When an Event is rescheduled (StartDateTime is changed), log the original and new date/time in a custom
object Calendar_Audit__c. This should only happen if the date is actually changed.

Trigger:
trigger EventTrigger on Event (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link], [Link]);
}
}
}

Trigger Handler:
public class EventTriggerHandler {
public static void handleAfterUpdate(List<Event> newList, Map<Id, Event> oldMap) {
List<Calendar_Audit__c> audits = new List<Calendar_Audit__c>();

for (Event e : newList) {


Event old = [Link]([Link]);
if ([Link] != [Link]) {
[Link](new Calendar_Audit__c(
Event__c = [Link],
Old_DateTime__c = [Link],
New_DateTime__c = [Link],
Reason__c = 'Event rescheduled'
));
}
}

if (![Link]()) insert audits;


}
}

Test Class:
@isTest
private class EventTriggerHandlerTest {
@isTest static void testEventRescheduleAudit() {
Event e = new Event(Subject='Team Meeting', StartDateTime=[Link]().addDays(1), EndDateTime=Sy
insert e;

[Link] = [Link]().addDays(2);
update e;

List<Calendar_Audit__c> audits = [SELECT Id, Old_DateTime__c, New_DateTime__c FROM Calendar_Audit


[Link](1, [Link]());
[Link](audits[0].Old_DateTime__c, audits[0].New_DateTime__c);
}
}
Trigger Scenario: Invoice__c Trigger: Auto-Create Payment__c and
Validate Amount

Problem Statement:
When an Invoice__c is inserted, automatically create a related Payment__c record with status 'Pending'.
Also, in before insert, throw an error if Amount__c is less than or equal to zero.

Trigger:
trigger InvoiceTrigger on Invoice__c (before insert, after insert) {
switch on [Link] {
when BEFORE_INSERT {
[Link]([Link]);
}
when AFTER_INSERT {
[Link]([Link]);
}
}
}

Trigger Handler:
public class InvoiceTriggerHandler {
public static void handleBeforeInsert(List<Invoice__c> invoices) {
for (Invoice__c inv : invoices) {
if (inv.Amount__c <= 0) {
[Link]('Invoice amount must be greater than zero.');
}
}
}

public static void handleAfterInsert(List<Invoice__c> invoices) {


List<Payment__c> payments = new List<Payment__c>();
for (Invoice__c inv : invoices) {
[Link](new Payment__c(
Invoice__c = [Link],
Amount__c = inv.Amount__c,
Status__c = 'Pending',
Due_Date__c = inv.Due_Date__c
));
}
if (![Link]()) {
insert payments;
}
}
}

Test Class:
@isTest
private class InvoiceTriggerHandlerTest {
@isTest static void testValidInvoiceCreatesPayment() {
Invoice__c inv = new Invoice__c(Name='INV-001', Amount__c=500, Due_Date__c=[Link]().addDays
insert inv;

List<Payment__c> payments = [SELECT Id FROM Payment__c WHERE Invoice__c = :[Link]];


[Link](1, [Link]());
}

@isTest static void testInvalidInvoiceAmount() {


Invoice__c inv = new Invoice__c(Name='INV-002', Amount__c=0);
[Link]();
try {
insert inv;
[Link](false, 'Expected error for invalid amount');
} catch (DmlException e) {
[Link]([Link]().contains('greater than zero'));
}
[Link]();
}
}
Trigger Scenario: User Trigger: Log Role Changes into
User_Change_History__c

Problem Statement:
When a User's Role is changed, log the previous and new Role into a custom object
User_Change_History__c with a timestamp and who made the change. Bulk-safe and after update logic
required.

Trigger:
trigger UserTrigger on User (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link], [Link]);
}
}
}

Trigger Handler:
public class UserTriggerHandler {
public static void handleAfterUpdate(List<User> newList, Map<Id, User> oldMap) {
List<User_Change_History__c> changes = new List<User_Change_History__c>();

for (User u : newList) {


User old = [Link]([Link]);
if ([Link] != [Link]) {
[Link](new User_Change_History__c(
User__c = [Link],
Old_Role__c = [Link],
New_Role__c = [Link],
Changed_By__c = [Link](),
Change_Timestamp__c = [Link]()
));
}
}

if (![Link]()) insert changes;


}
}

Test Class:
@isTest
private class UserTriggerHandlerTest {
@isTest static void testUserRoleChangeLogged() {
Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User' LIMIT 1];
UserRole role1 = new UserRole(Name='Role A');
UserRole role2 = new UserRole(Name='Role B');
insert new List<UserRole>{role1, role2};

User u = new User(Username='testuser1@[Link]', Email='testuser1@[Link]',


LastName='User', Alias='tuser', TimeZoneSidKey='America/Los_Angeles',
LocaleSidKey='en_US', EmailEncodingKey='UTF-8',
ProfileId=[Link], LanguageLocaleKey='en_US', UserRoleId=[Link]);
insert u;

[Link] = [Link];
update u;

List<User_Change_History__c> logs = [SELECT Id FROM User_Change_History__c WHERE User__c = :[Link]]


[Link](1, [Link]());
}
}
Trigger Scenario: Case Trigger: Escalation Handling with Audit Log and
Task Creation

Problem Statement:
When a Case is updated and its status changes to 'Escalated', the system should: 1. Create a high-priority
Task for follow-up 2. Insert a record into the Case_Audit__c custom object This logic must be bulk-safe and
include recursive protection.

Trigger:
trigger CaseTrigger on Case (after update) {
switch on [Link] {
when AFTER_UPDATE {
if (![Link]()) {
[Link]();
[Link]([Link], [Link]);
}
}
}
}

Trigger Handler:
public class CaseTriggerHandler {
public static void handleAfterUpdate(List<Case> newList, Map<Id, Case> oldMap) {
List<Task> tasksToInsert = new List<Task>();
List<Case_Audit__c> auditsToInsert = new List<Case_Audit__c>();

for (Case c : newList) {


Case old = [Link]([Link]);
if ([Link] == 'Escalated' && [Link] != 'Escalated') {
[Link](new Task(
WhatId = [Link],
Subject = 'Follow-up: Escalated Case',
Priority = 'High',
Status = 'Not Started'
));
[Link](new Case_Audit__c(
Case__c = [Link],
Action__c = 'Status changed to Escalated',
Performed_By__c = [Link](),
Action_Date__c = [Link]()
));
}
}

if (![Link]()) insert tasksToInsert;


if (![Link]()) insert auditsToInsert;
}
}

Test Class:
@isTest
private class CaseTriggerHandlerTest {
@isTest static void testEscalationLogic() {
Case c = new Case(Subject='Test Case', Status='New');
insert c;

[Link] = 'Escalated';
update c;

List<Task> tasks = [SELECT Id FROM Task WHERE WhatId = :[Link]];


[Link](1, [Link]());

List<Case_Audit__c> audits = [SELECT Id FROM Case_Audit__c WHERE Case__c = :[Link]];


[Link](1, [Link]());
}
}
Trigger Scenario: Account Trigger: Aggregate Contact Count on Type
Change

Problem Statement:
When an Account's Type is changed to 'Customer', count the number of related active Contacts and update a
custom field Total_Contacts__c on the Account. The logic must be bulk-safe and avoid unnecessary DML.

Trigger:
trigger AccountTrigger on Account (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link], [Link]);
}
}
}

Trigger Handler:
public class AccountTriggerHandler {
public static void handleAfterUpdate(List<Account> newList, Map<Id, Account> oldMap) {
Set<Id> changedAccounts = new Set<Id>();

for (Account acc : newList) {


Account old = [Link]([Link]);
if ([Link] == 'Customer' && [Link] != 'Customer') {
[Link]([Link]);
}
}

if (![Link]()) {
Map<Id, Integer> contactCounts = new Map<Id, Integer>();
for (AggregateResult ar : [
SELECT AccountId, COUNT(Id) contactCount
FROM Contact
WHERE AccountId IN :changedAccounts AND IsDeleted = false
GROUP BY AccountId
]) {
[Link]((Id)[Link]('AccountId'), (Integer)[Link]('contactCount'));
}

List<Account> toUpdate = new List<Account>();


for (Id accId : changedAccounts) {
[Link](new Account(Id = accId, Total_Contacts__c = [Link](accId)));
}

if (![Link]()) update toUpdate;


}
}
}

Test Class:
@isTest
private class AccountTriggerHandlerTest {
@isTest static void testContactAggregation() {
Account acc = new Account(Name='Test Account', Type='Prospect');
insert acc;

insert new List<Contact>{


new Contact(LastName='One', AccountId=[Link]),
new Contact(LastName='Two', AccountId=[Link])
};

[Link] = 'Customer';
update acc;
Account updated = [SELECT Total_Contacts__c FROM Account WHERE Id = :[Link]];
[Link](2, updated.Total_Contacts__c);
}
}
Trigger Scenario: Lead Trigger: Sync Converted Leads and Async
External Push

Problem Statement:
When a Lead is converted, a record should be created in a custom object Lead_Sync__c. Also, enqueue a
Queueable class to simulate an async sync with an external system. Ensure the trigger is bulk-safe and
ignores already synced records.

Trigger:
trigger LeadTrigger on Lead (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link], [Link]);
}
}
}

Trigger Handler:
public class LeadTriggerHandler {
public static void handleAfterUpdate(List<Lead> newList, Map<Id, Lead> oldMap) {
List<Lead_Sync__c> syncs = new List<Lead_Sync__c>();
Set<Id> toSync = new Set<Id>();

for (Lead l : newList) {


Lead old = [Link]([Link]);
if (![Link] && [Link]) {
[Link](new Lead_Sync__c(
Lead__c = [Link],
Converted_Account__c = [Link],
Converted_Contact__c = [Link]
));
[Link]([Link]);
}
}

if (![Link]()) insert syncs;

if (![Link]()) {
[Link](new PushLeadToExternalSystemQueueable(toSync));
}
}
}

public class PushLeadToExternalSystemQueueable implements Queueable {


private Set<Id> leadIds;
public PushLeadToExternalSystemQueueable(Set<Id> leadIds) {
[Link] = leadIds;
}

public void execute(QueueableContext context) {


// Simulate external push logic
[Link]('Syncing leads externally: ' + leadIds);
}
}

Test Class:
@isTest
private class LeadTriggerHandlerTest {
@isTest static void testLeadSyncAndQueueable() {
Lead l = new Lead(LastName='Test Lead', Company='Test Co');
insert l;

[Link] = true;
[Link] = [Link](); // Dummy value for test
[Link] = [Link](); // Dummy value for test

update l;

List<Lead_Sync__c> syncs = [SELECT Id FROM Lead_Sync__c WHERE Lead__c = :[Link]];


[Link](1, [Link]());

[Link]();
[Link](new PushLeadToExternalSystemQueueable(new Set<Id>{[Link]}));
[Link]();
}
}
Trigger Scenario: Contract Trigger: Auto-Creation of Renewal
Opportunity

Problem Statement:
When a Contract is nearing its end date (within 30 days) and Renewal_Opportunity__c is not already set,
automatically create a Renewal Opportunity and link it to the Contract. Ensure this is done only once using a
status flag.

Trigger:
trigger ContractTrigger on Contract (after insert, after update) {
switch on [Link] {
when AFTER_INSERT, AFTER_UPDATE {
[Link]([Link]);
}
}
}

Trigger Handler:
public class ContractTriggerHandler {
public static void handleAfter(List<Contract> contracts) {
List<Opportunity> renewalOpps = new List<Opportunity>();
Map<Id, Contract> toUpdate = new Map<Id, Contract>();

for (Contract c : contracts) {


if ([Link] != null &&
[Link] <= [Link]().addDays(30) &&
c.Renewal_Opportunity__c == null &&
[Link] != null) {

Opportunity renewal = new Opportunity(


Name = 'Renewal - ' + [Link],
AccountId = [Link],
CloseDate = [Link],
StageName = 'Prospecting',
Type = 'Renewal'
);
[Link](renewal);
[Link]([Link], c);
}
}

if (![Link]()) {
insert renewalOpps;

List<Contract> contractsToUpdate = new List<Contract>();


Integer index = 0;
for (Contract c : [Link]()) {
c.Renewal_Opportunity__c = renewalOpps[index].Id;
[Link](c);
index++;
}

if (![Link]()) update contractsToUpdate;


}
}
}

Test Class:
@isTest
private class ContractTriggerHandlerTest {
@isTest static void testRenewalOpportunityCreation() {
Account acc = new Account(Name='Test Account');
insert acc;
Contract con = new Contract(
AccountId = [Link],
Status = 'Activated',
StartDate = [Link]().addDays(-30),
EndDate = [Link]().addDays(10)
);
insert con;

Contract updated = [SELECT Id, Renewal_Opportunity__c FROM Contract WHERE Id = :[Link]];


[Link](null, updated.Renewal_Opportunity__c);

Opportunity opp = [SELECT Id FROM Opportunity WHERE Id = :updated.Renewal_Opportunity__c];


[Link]('Renewal - ' + [Link], [Link]);
}
}
Trigger Scenario: Quote Trigger: Prevent Approval Without Line Items

Problem Statement:
When a Quote is updated and the Status is changed to 'Approved', ensure it has at least one QuoteLineItem.
If not, prevent the update by adding an error. The logic must be handled in before update context.

Trigger:
trigger QuoteTrigger on Quote (before update) {
switch on [Link] {
when BEFORE_UPDATE {
[Link]([Link]);
}
}
}

Trigger Handler:
public class QuoteTriggerHandler {
public static void handleBeforeUpdate(List<Quote> quotes) {
Set<Id> quoteIdsToCheck = new Set<Id>();

for (Quote q : quotes) {


if ([Link] == 'Approved') {
[Link]([Link]);
}
}

if (![Link]()) {
Map<Id, Integer> lineItemCounts = new Map<Id, Integer>();
for (AggregateResult ar : [
SELECT QuoteId, COUNT(Id) cnt FROM QuoteLineItem
WHERE QuoteId IN :quoteIdsToCheck
GROUP BY QuoteId
]) {
[Link]((Id) [Link]('QuoteId'), (Integer) [Link]('cnt'));
}

for (Quote q : quotes) {


if ([Link] == 'Approved' && ([Link]([Link]) == null || [Link](q.I
[Link]('Cannot approve a Quote without at least one line item.');
}
}
}
}
}

Test Class:
@isTest
private class QuoteTriggerHandlerTest {
@isTest static void testApprovalBlockedWithoutLineItems() {
Quote q = new Quote(Name='Test Quote', Status='Draft');
insert q;

[Link] = 'Approved';

[Link]();
try {
update q;
[Link](false, 'Expected error due to no line items');
} catch (DmlException e) {
[Link]([Link]().contains('Cannot approve a Quote without at least one line item.
}
[Link]();
}
}
Trigger Scenario: Campaign Trigger: Budget Aggregation from
Campaign Members

Problem Statement:
When a Campaign is updated, aggregate the total Estimated_Cost__c from all related
CampaignMembers__c and update the Total_Estimated_Cost__c field on the Campaign. Use after update
and bulk-safe cross-object aggregation logic.

Trigger:
trigger CampaignTrigger on Campaign (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link]);
}
}
}

Trigger Handler:
public class CampaignTriggerHandler {
public static void handleAfterUpdate(List<Campaign> campaigns) {
Set<Id> campaignIds = new Set<Id>();
for (Campaign c : campaigns) {
[Link]([Link]);
}

Map<Id, Decimal> totals = new Map<Id, Decimal>();


for (AggregateResult ar : [
SELECT Campaign__c, SUM(Estimated_Cost__c) totalCost
FROM CampaignMember__c
WHERE Campaign__c IN :campaignIds
GROUP BY Campaign__c
]) {
[Link]((Id) [Link]('Campaign__c'), (Decimal) [Link]('totalCost'));
}

List<Campaign> updates = new List<Campaign>();


for (Campaign c : campaigns) {
Decimal total = [Link]([Link]);
if (total != null) {
[Link](new Campaign(Id = [Link], Total_Estimated_Cost__c = total));
}
}

if (![Link]()) update updates;


}
}

Test Class:
@isTest
private class CampaignTriggerHandlerTest {
@isTest static void testCostAggregation() {
Campaign camp = new Campaign(Name='Test Campaign');
insert camp;

insert new List<CampaignMember__c>{


new CampaignMember__c(Campaign__c=[Link], Estimated_Cost__c=100),
new CampaignMember__c(Campaign__c=[Link], Estimated_Cost__c=200)
};

update camp;

Campaign updated = [SELECT Total_Estimated_Cost__c FROM Campaign WHERE Id = :[Link]];


[Link](300, updated.Total_Estimated_Cost__c);
}
}
Trigger Scenario: Custom_Object__c Trigger: Auto-Link to Account
Based on Region

Problem Statement:
When a Custom_Object__c record is inserted, auto-link it to an Account whose Region__c matches. The field
Linked_Account__c should be updated accordingly. Ensure this is done in before insert and is bulk-safe.

Trigger:
trigger CustomObjectTrigger on Custom_Object__c (before insert) {
switch on [Link] {
when BEFORE_INSERT {
[Link]([Link]);
}
}
}

Trigger Handler:
public class CustomObjectTriggerHandler {
public static void handleBeforeInsert(List<Custom_Object__c> records) {
Set<String> regions = new Set<String>();
for (Custom_Object__c rec : records) {
if (rec.Region__c != null) {
[Link](rec.Region__c);
}
}

Map<String, Account> accountsByRegion = new Map<String, Account>();


for (Account acc : [SELECT Id, Region__c FROM Account WHERE Region__c IN :regions]) {
[Link](acc.Region__c, acc);
}

for (Custom_Object__c rec : records) {


if (rec.Region__c != null && [Link](rec.Region__c)) {
rec.Linked_Account__c = [Link](rec.Region__c).Id;
}
}
}
}

Test Class:
@isTest
private class CustomObjectTriggerHandlerTest {
@isTest static void testAccountLinkingByRegion() {
Account acc = new Account(Name='East Account', Region__c='East');
insert acc;

Custom_Object__c customRec = new Custom_Object__c(Name='Test', Region__c='East');


insert customRec;

Custom_Object__c result = [SELECT Linked_Account__c FROM Custom_Object__c WHERE Id = :customRec.I


[Link]([Link], result.Linked_Account__c);
}
}
Trigger Scenario: Product2 Trigger: Notify on Discontinued Flag via
Chatter Post

Problem Statement:
When a Product2 record is updated and its IsDiscontinued field is set to true, post a Chatter message on the
Product2 record to notify internal users. This should only happen once.

Trigger:
trigger Product2Trigger on Product2 (after update) {
switch on [Link] {
when AFTER_UPDATE {
[Link]([Link], [Link]);
}
}
}

Trigger Handler:
public class Product2TriggerHandler {
public static void handleAfterUpdate(List<Product2> newList, Map<Id, Product2> oldMap) {
List<FeedItem> chatterPosts = new List<FeedItem>();

for (Product2 prod : newList) {


Product2 old = [Link]([Link]);
if ([Link] && ![Link]) {
[Link](new FeedItem(
ParentId = [Link],
Body = 'This product has been marked as Discontinued. Please update related orders or
Type = 'TextPost'
));
}
}

if (![Link]()) {
insert chatterPosts;
}
}
}

Test Class:
@isTest
private class Product2TriggerHandlerTest {
@isTest static void testChatterNotificationOnDiscontinue() {
Product2 prod = new Product2(Name='Test Product', IsActive=true);
insert prod;

[Link] = true;
update prod;

List<FeedItem> posts = [SELECT Id, ParentId FROM FeedItem WHERE ParentId = :[Link]];
[Link](1, [Link]());
}
}

You might also like