You need to sign in to do that
Don't have an account?

Advance Apex Specialist Step 6 - Stuck on that challenge
Hi, I am facing error - Ensure that you implement the Queueable interface in the AnnouncementQueueable class.
I am getting proper response....and implemented trigger, Product2Helper and AnnouncementQueable class as per the trailhead
Follwoing is my code -
product2Trigger --->
trigger product2Trigger on Product2 (after update) {
Product2Helper.AfterUpdate((List<Product2>)trigger.new,(List<Product2>)trigger.old);
}
Product2Helper Class ---->
public class Product2Helper {
/**
* @name COLLABORATION_GROUP
* @description List of CollaborationGroup used in both business and test logic
**/
static List<CollaborationGroup> COLLABORATION_GROUP = [
SELECT Id
FROM CollaborationGroup
WHERE Name = :Constants.INVENTORY_ANNOUNCEMENTS
OR Name = :('TEST'+Constants.INVENTORY_ANNOUNCEMENTS)
LIMIT 1
];
/**
* @name afterUpdate
* @description called by product2 Trigger on After Update
* @param List<Product2> newList
* @param List<Product2> oldList
**/
public static void AfterUpdate(List<Product2> prodList, List<Product2> prodOldList){
//ToDo: Declare a List of Product2 records named needsAnnouncement
//ToDo: Declare a Map of Strings to Inventory_Setting__mdt records
//ToDo: Loop through a query of Inventory_Setting__mdt records and populate the Map with Name as the key
//ToDo: Loop through the Products in newList
// Use the corresponding Inventory Setting record to determine the correct Low Quantity Alert
// If the Product's Quantity Remaining has been changed to less than the Low Quantity Alert
// add it to the needsAnnouncement list
//ToDo: Pass records to the postAlerts method
List<Product2> needsAnnouncement = new List<Product2>();
Map<String,Inventory_Setting__mdt> mapInventory = new Map<String,Inventory_Setting__mdt>();
for(Inventory_Setting__mdt inv : [select id, DeveloperName, Low_Quantity_Alert__c from Inventory_Setting__mdt]){
mapInventory.put(inv.DeveloperName,inv);
}
for(integer i=0;i<prodList.size();i++)
{
if(mapInventory.get(prodList[i].Family).Low_Quantity_Alert__c > prodList[i].Quantity_Remaining__c &&
mapInventory.get(prodList[i].Family).Low_Quantity_Alert__c <= prodOldList[i].Quantity_Remaining__c)
{
needsAnnouncement.add(prodList[i]);
}
}
PostAlerts(needsAnnouncement);
}
/**
* @name postAlerts
* @description called by product2 Trigger on After Update
* @param List<Product2> productList
**/
public static void PostAlerts(List<Product2> productList){
List<ConnectApi.AnnouncementInput> toPost = new List<ConnectApi.AnnouncementInput>();
for ( Product2 p : productList ){
// ToDo: Construct a new AnnouncementInput for the Chatter Group so that it:
// expires in a day
// does not notify users via email.
// and has a text body that includes the name of the product followed by the INVENTORY_LEVEL_LOW constant
ConnectApi.MessageBodyInput msgBody = new ConnectApi.MessageBodyInput();
ConnectApi.AnnouncementInput tempPost = new ConnectApi.AnnouncementInput();
ConnectApi.TextSegmentInput textSegment = new ConnectApi.TextSegmentInput();
textSegment.text = p.Name +' '+ Constants.INVENTORY_LEVEL_LOW;
msgBody.messageSegments = new List<ConnectApi.MessageSegmentInput>();
msgBody.messageSegments.add(textSegment);
tempPost.body = msgBody;
tempPost.expirationDate = DateTime.Now().AddDays(1);
tempPost.parentId = COLLABORATION_GROUP[0].id;
tempPost.sendEmails = false;
toPost.add(tempPost);
}
// ToDo: Create and enqueue an instance of the announcementQueuable class with the list of Products
AnnouncementQueueable annQue = new AnnouncementQueueable(toPost);
//annQue.toPost = toPost;
system.enqueueJob(annQue);
}
}
AnnouncementQueueable Class ---->
/**
* @name AnnouncementQueueable
* @description This class posts Chatter Announcements
**/
public class AnnouncementQueueable implements Queueable{
public List<ConnectApi.AnnouncementInput> toPost;
public AnnouncementQueueable(List<ConnectApi.AnnouncementInput> annList)
{
toPost = annList;
}
//ToDo: Modify this class to implement the Queueable interface and call the postAnnouncements method
public void execute(System.QueueableContext context){
PostAnnouncements(toPost);
}
/**
* @name postAnnouncements
* @description This method is provided for you to facilitate the Super Badge
**/
public static void PostAnnouncements(List<ConnectApi.AnnouncementInput> announcements){
while ( announcements.size() > 0 ){
if ( Limits.getDMLStatements() < Limits.getLimitDMLStatements() && !test.isRunningTest() ){
ConnectApi.AnnouncementInput a = announcements.remove(0);
ConnectApi.Announcements.postAnnouncement('Internal', a);
} else {
break;
}
}
if ( announcements.size() > 0 && !test.isRunningTest() ){
AnnouncementQueueable q = new AnnouncementQueueable(announcements);
//q.toPost = announcements;
system.enqueueJob(q);
//ToDo: Enqueue the above instance of announcementQueueable
}
}
}
Any help would be really appreciated.
I am getting proper response....and implemented trigger, Product2Helper and AnnouncementQueable class as per the trailhead
Follwoing is my code -
product2Trigger --->
trigger product2Trigger on Product2 (after update) {
Product2Helper.AfterUpdate((List<Product2>)trigger.new,(List<Product2>)trigger.old);
}
Product2Helper Class ---->
public class Product2Helper {
/**
* @name COLLABORATION_GROUP
* @description List of CollaborationGroup used in both business and test logic
**/
static List<CollaborationGroup> COLLABORATION_GROUP = [
SELECT Id
FROM CollaborationGroup
WHERE Name = :Constants.INVENTORY_ANNOUNCEMENTS
OR Name = :('TEST'+Constants.INVENTORY_ANNOUNCEMENTS)
LIMIT 1
];
/**
* @name afterUpdate
* @description called by product2 Trigger on After Update
* @param List<Product2> newList
* @param List<Product2> oldList
**/
public static void AfterUpdate(List<Product2> prodList, List<Product2> prodOldList){
//ToDo: Declare a List of Product2 records named needsAnnouncement
//ToDo: Declare a Map of Strings to Inventory_Setting__mdt records
//ToDo: Loop through a query of Inventory_Setting__mdt records and populate the Map with Name as the key
//ToDo: Loop through the Products in newList
// Use the corresponding Inventory Setting record to determine the correct Low Quantity Alert
// If the Product's Quantity Remaining has been changed to less than the Low Quantity Alert
// add it to the needsAnnouncement list
//ToDo: Pass records to the postAlerts method
List<Product2> needsAnnouncement = new List<Product2>();
Map<String,Inventory_Setting__mdt> mapInventory = new Map<String,Inventory_Setting__mdt>();
for(Inventory_Setting__mdt inv : [select id, DeveloperName, Low_Quantity_Alert__c from Inventory_Setting__mdt]){
mapInventory.put(inv.DeveloperName,inv);
}
for(integer i=0;i<prodList.size();i++)
{
if(mapInventory.get(prodList[i].Family).Low_Quantity_Alert__c > prodList[i].Quantity_Remaining__c &&
mapInventory.get(prodList[i].Family).Low_Quantity_Alert__c <= prodOldList[i].Quantity_Remaining__c)
{
needsAnnouncement.add(prodList[i]);
}
}
PostAlerts(needsAnnouncement);
}
/**
* @name postAlerts
* @description called by product2 Trigger on After Update
* @param List<Product2> productList
**/
public static void PostAlerts(List<Product2> productList){
List<ConnectApi.AnnouncementInput> toPost = new List<ConnectApi.AnnouncementInput>();
for ( Product2 p : productList ){
// ToDo: Construct a new AnnouncementInput for the Chatter Group so that it:
// expires in a day
// does not notify users via email.
// and has a text body that includes the name of the product followed by the INVENTORY_LEVEL_LOW constant
ConnectApi.MessageBodyInput msgBody = new ConnectApi.MessageBodyInput();
ConnectApi.AnnouncementInput tempPost = new ConnectApi.AnnouncementInput();
ConnectApi.TextSegmentInput textSegment = new ConnectApi.TextSegmentInput();
textSegment.text = p.Name +' '+ Constants.INVENTORY_LEVEL_LOW;
msgBody.messageSegments = new List<ConnectApi.MessageSegmentInput>();
msgBody.messageSegments.add(textSegment);
tempPost.body = msgBody;
tempPost.expirationDate = DateTime.Now().AddDays(1);
tempPost.parentId = COLLABORATION_GROUP[0].id;
tempPost.sendEmails = false;
toPost.add(tempPost);
}
// ToDo: Create and enqueue an instance of the announcementQueuable class with the list of Products
AnnouncementQueueable annQue = new AnnouncementQueueable(toPost);
//annQue.toPost = toPost;
system.enqueueJob(annQue);
}
}
AnnouncementQueueable Class ---->
/**
* @name AnnouncementQueueable
* @description This class posts Chatter Announcements
**/
public class AnnouncementQueueable implements Queueable{
public List<ConnectApi.AnnouncementInput> toPost;
public AnnouncementQueueable(List<ConnectApi.AnnouncementInput> annList)
{
toPost = annList;
}
//ToDo: Modify this class to implement the Queueable interface and call the postAnnouncements method
public void execute(System.QueueableContext context){
PostAnnouncements(toPost);
}
/**
* @name postAnnouncements
* @description This method is provided for you to facilitate the Super Badge
**/
public static void PostAnnouncements(List<ConnectApi.AnnouncementInput> announcements){
while ( announcements.size() > 0 ){
if ( Limits.getDMLStatements() < Limits.getLimitDMLStatements() && !test.isRunningTest() ){
ConnectApi.AnnouncementInput a = announcements.remove(0);
ConnectApi.Announcements.postAnnouncement('Internal', a);
} else {
break;
}
}
if ( announcements.size() > 0 && !test.isRunningTest() ){
AnnouncementQueueable q = new AnnouncementQueueable(announcements);
//q.toPost = announcements;
system.enqueueJob(q);
//ToDo: Enqueue the above instance of announcementQueueable
}
}
}
Any help would be really appreciated.
I would suggest you refer below link for similar discussion.
https://developer.salesforce.com/forums/?id=9060G0000005O9cQAE
Please mark it as solved if my reply was helpful. It will make it available for other as the proper solution.
Best Regards
Sandhya
All Answers
I would suggest you refer below link for similar discussion.
https://developer.salesforce.com/forums/?id=9060G0000005O9cQAE
Please mark it as solved if my reply was helpful. It will make it available for other as the proper solution.
Best Regards
Sandhya
public class AnnouncementQueueable implements Queueable{
public List<ConnectApi.AnnouncementInput> toPost {get;set;}
public void execute(System.QueueableContext context) {
PostAnnouncements(this.toPost);
}
public static void PostAnnouncements(List<ConnectApi.AnnouncementInput> announcements){
System.debug('Post Announcements: ' + announcements);
while ( announcements.size() > 0 ){
if ( Limits.getDMLStatements() < Limits.getLimitDMLStatements() && !test.isRunningTest() ){
ConnectApi.AnnouncementInput a = announcements.remove(0);
System.debug('a: ' + a);
ConnectApi.Announcements.postAnnouncement('Internal', a);
} else {
break;
}
}
if ( announcements.size() > 0 && !test.isRunningTest() ){
AnnouncementQueueable q = new AnnouncementQueueable();
q.toPost = announcements;
System.enqueueJob(q);
}
}
}
Anyone can help?
public void execute(System.QueueableContext context) {
Please ensure that when a Product's Quantity Remaining falls below its low level alert, an announcement is posted to the chatter group.
Product2Helper Class
public class Product2Helper {
/**
* @name COLLABORATION_GROUP
* @description List of CollaborationGroup used in both business and test logic
**/
static List<CollaborationGroup> COLLABORATION_GROUP = [
SELECT Id
FROM CollaborationGroup
WHERE Name = :Constants.INVENTORY_ANNOUNCEMENTS
OR Name = :('TEST'+Constants.INVENTORY_ANNOUNCEMENTS)
LIMIT 1
];
/**
* @name afterUpdate
* @description called by product2 Trigger on After Update
* @param List<Product2> newList
* @param List<Product2> oldList
**/
public static void AfterUpdate(List<Product2> newList, List<Product2> oldList){
//ToDo: Declare a List of Product2 records named needsAnnouncement
List<Product2> needsAnnouncement = new List<Product2>();
//ToDo: Declare a Map of Strings to Inventory_Setting__mdt records
Map<String,Inventory_Setting__mdt> inventorySettings = new Map<String,Inventory_Setting__mdt>();
//ToDo: Loop through a query of Inventory_Setting__mdt records and populate the Map with Name as the key
for (Inventory_Setting__mdt inventorySetting : [SELECT Id, Low_Quantity_Alert__c, QualifiedApiName, DeveloperName, MasterLabel FROM Inventory_Setting__mdt]) {
inventorySettings.put(inventorySetting.DeveloperName, inventorySetting);
}
//ToDo: Loop through the Products in newList
// Use the corresponding Inventory Setting record to determine the correct Low Quantity Alert
// If the Product's Quantity Remaining has been changed to less than the Low Quantity Alert
// add it to the needsAnnouncement list
for(Product2 newProd : newList) {
if(inventorySettings.get(newProd.family)!= null &&
newProd.Quantity_Remaining__c < inventorySettings.get(newProd.family).Low_Quantity_Alert__c) {
needsAnnouncement.add(newProd);
}
}
//ToDo: Pass records to the postAlerts method
PostAlerts(needsAnnouncement);
}
/**
* @name postAlerts
* @description called by product2 Trigger on After Update
* @param List<Product2> productList
**/
public static void PostAlerts(List<Product2> productList){
List<ConnectApi.AnnouncementInput> toPost = new List<ConnectApi.AnnouncementInput>();
for ( Product2 p : productList ){
// ToDo: Construct a new AnnouncementInput for the Chatter Group so that it:
ConnectApi.AnnouncementInput input = new ConnectApi.AnnouncementInput();
// expires in a day
input.expirationDate = Date.today().addDays(1);
// does not notify users via email.
input.sendEmails = false;
ConnectApi.MessageBodyInput bodyInput = new ConnectApi.MessageBodyInput();
ConnectApi.TextSegmentInput textInput = new ConnectApi.TextSegmentInput();
// and has a text body that includes the name of the product followed by the INVENTORY_LEVEL_LOW constant
textInput.text = p.Name + ' , ' + Constants.INVENTORY_LEVEL_LOW;
bodyInput.messageSegments = new List<ConnectApi.TextSegmentInput>();
bodyInput.messageSegments.add(textInput);
input.body = bodyInput;
input.parentId = COLLABORATION_GROUP[0].Id;
toPost.add(input);
}
// ToDo: Create and enqueue an instance of the announcementQueuable class with the list of Products
AnnouncementQueueable annQueueable = new AnnouncementQueueable();
annQueueable.toPost = toPost;
System.enqueueJob(annQueueable);
}
}
Product2Trigger
/**
* @name product2Trigger
* @description Trigger to notify staff of low levels of inventory
**/
trigger product2Trigger on Product2 (after update) {
Product2Helper.AfterUpdate(Trigger.new, Trigger.old);
}
AnnouncementQueueable Class
/**
* @name AnnouncementQueueable
* @description This class posts Chatter Announcements
**/
public class AnnouncementQueueable implements Queueable{
public List<ConnectApi.AnnouncementInput> toPost;
//ToDo: Modify this class to implement the Queueable interface and call the postAnnouncements method
public void execute(QueueableContext context) {
PostAnnouncements(toPost);
}
/**
* @name postAnnouncements
* @description This method is provided for you to facilitate the Super Badge
**/
public static void PostAnnouncements(List<ConnectApi.AnnouncementInput> announcements){
while ( announcements.size() > 0 ){
if ( Limits.getDMLStatements() < Limits.getLimitDMLStatements() && !test.isRunningTest() ){
ConnectApi.AnnouncementInput a = announcements.remove(0);
ConnectApi.Announcements.postAnnouncement('Internal', a);
} else {
break;
}
}
if ( announcements.size() > 0 && !test.isRunningTest() ){
AnnouncementQueueable q = new AnnouncementQueueable();
q.toPost = announcements;
//ToDo: Enqueue the above instance of announcementQueueable
System.enqueueJob(q);
}
}
}
Any one can help me?
You still facing this issue? I too encountered same issue and checked log file and saw 0 records then I corrected.
If yes, this will be due to queue job not executing or typo with group name. Use same code and call the queueable class(AnnouncementQueueable) from execute in anonymous window. Verify in your Org if the naming of the chatter group and announcements are posted.
Thanks,
Vinay