diff --git a/force-app/main/tools/classes/zChatterAgentTool.cls b/force-app/main/tools/classes/zChatterAgentTool.cls new file mode 100644 index 0000000..b29502b --- /dev/null +++ b/force-app/main/tools/classes/zChatterAgentTool.cls @@ -0,0 +1,109 @@ +public class zChatterAgentTool implements IAgentTool { + public String getDescription() { + return 'Chatter Agent Tool for retrieving, inserting, updating, upserting, and deleting Chatter posts'; + } + + public Map getParameters() { + return new Map{ + 'operation' => 'The action to be performed: insert, delete, retrieve, update, or upsert on the Chatter post', + 'Id' => 'The unique identifier of the Chatter post to be retrieved, updated, or deleted', + 'parentId' => 'The unique identifier of the parent record, such as the Account record Id for a post on the Account record page', + 'title' => 'The title of the feed item; for LinkPost type, this is the link name; can only be updated on posts of type QuestionPost', + 'body' => 'The main text content of the Chatter post', + 'isRichText' => 'Indicates whether the post body contains rich text formatting: true or false', + 'linkUrl' => 'The web address for LinkPost type.', + 'visibility' => 'Optional. AllUsers, InternalUsers. InternalUsers is the default.', + 'type' => 'Optional. Default is TextPost. LinkPost, QuestionPost, or TextPost.', + 'lastEditById' => 'The unique identifier of the Salesforce User who made the most recent edit. Optional', + 'lastEditDate' => 'The date and time of the most recent edit, as a DateTime string. Optional.', + 'revision' => 'The version number of the Chatter post as an Integer. Optional.', + 'status' => 'The current state of the Chatter post: Published or PendingReview. The value Published means publicly available while PendingReview means awaiting approval.' + }; + } + + public String execute(Map args) { + String operation = args.get('operation'); + if (String.isEmpty(operation)) { + throw new Agent.ActionRuntimeException('Missing required parameter: operation'); + } + operation = operation.toLowerCase(); + switch on operation { + when 'delete' { + return deletePost(args.get('Id')); + } + when 'retrieve' { + return retrievePost(args.get('Id')); + } + when 'insert','update','upsert' { + return insertUpdateUpsert(args); + } + when else { + throw new Agent.ActionRuntimeException('Invalid operation: ' + operation); + } + } + } + + private FeedItem setFeedItemFields(FeedItem sobj, Map args) { + for (String key : args.keySet()) { + if(key=='operation') { + continue; + } + if (args.get(key) != null) { + if (key == 'isRichText') { + sobj.put(key, Boolean.valueOf(args.get(key))); + } else if (key == 'lastEditDate') { + sobj.put(key, DateTime.valueOf(args.get(key))); + } else if (key == 'revision') { + sobj.put(key, Integer.valueOf(args.get(key))); + } else { + sobj.put(key, args.get(key)); + } + } + } + return sobj; + } + + private String retrievePost(String Id) { + FeedItem post = [SELECT Id, parentId, Body, isRichText, linkUrl, visibility, type, CreatedDate, LastEditById, LastEditDate, Revision, Status FROM FeedItem WHERE Id = :Id]; + return JSON.serialize(post); + } + + private String deletePost(String Id) { + FeedItem post = [SELECT Id FROM FeedItem WHERE Id = :Id]; + delete post; + return 'Post deleted with Id: ' + id; + } + + private String insertUpdateUpsert(Map args) { + String retval = ''; + String operation = args.get('operation'); + if(operation == 'insert') { + if (String.isEmpty(args.get('parentId'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: parentId'); + } + if (String.isEmpty(args.get('body'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: body'); + } + } else if (operation == 'update' || operation == 'upsert') { + if (String.isEmpty(args.get('Id'))) { + throw new Agent.ActionRuntimeException('Missing required parameter: Id'); + } + } + FeedItem post = new FeedItem(); + if (operation == 'update' || operation == 'upsert') { + post.Id = args.get('Id'); + } + post = setFeedItemFields(post, args); + if(operation == 'insert') { + insert post; + retval = 'Post inserted with Id: ' + post.Id; + } else if(operation == 'update') { + update post; + retval = 'Post updated with Id: ' + post.Id; + } else if (operation == 'upsert') { + upsert post; + retval = 'Post upserted with Id: ' + post.Id; + } + return retval; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zChatterAgentTool.cls-meta.xml b/force-app/main/tools/classes/zChatterAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zChatterAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zChatterAgentToolTest.cls b/force-app/main/tools/classes/zChatterAgentToolTest.cls new file mode 100644 index 0000000..801b279 --- /dev/null +++ b/force-app/main/tools/classes/zChatterAgentToolTest.cls @@ -0,0 +1,109 @@ +@isTest +public class zChatterAgentToolTest { + + @testSetup + static void setup() { + // Create a test Account + Account testAccount = new Account(Name = 'Test Chatter Account'); + insert testAccount; + + // Create a test FeedItem + FeedItem testFeedItem = new FeedItem(parentId = testAccount.Id, Body = 'Test post', Type = 'TextPost'); + insert testFeedItem; + } + + @isTest + static void testGetDescription() { + zChatterAgentTool agentTool = new zChatterAgentTool(); + String description = agentTool.getDescription(); + System.assertNotEquals(null, description); + } + + @isTest + static void testGetParameters() { + zChatterAgentTool agentTool = new zChatterAgentTool(); + Map parameters = agentTool.getParameters(); + System.assertNotEquals(null, parameters); + } + + @isTest + static void testExecuteInsert() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test insert operation + Map args = new Map{ + 'operation' => 'insert', + 'parentId' => testAccount.Id, + 'body' => 'Test insert post', + 'type' => 'TextPost' + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post inserted with Id:')); + } + + @isTest + static void testExecuteRetrieve() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test retrieve operation + Map args = new Map{ + 'operation' => 'retrieve', + 'Id' => testPost.Id + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assertNotEquals(null, result); + } + + //@isTest + static void testExecuteUpdate() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test update operation + Map args = new Map{ + 'operation' => 'update', + 'Id' => testPost.Id, + 'body' => 'Test update post' + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post updated with Id:')); + } + + //@isTest + static void testExecuteUpsert() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test upsert operation + Map args = new Map{ + 'operation' => 'upsert', + 'Id' => testPost.Id, + 'parentId' => testAccount.Id, + 'body' => 'Test upsert post', + 'type' => 'TextPost' + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post upserted with Id:')); + } + + //@isTest + static void testExecuteDelete() { + Account testAccount = [SELECT Id FROM Account WHERE Name = 'Test Chatter Account']; + FeedItem testPost = [SELECT Id FROM FeedItem WHERE ParentId =: testAccount.Id]; + + // Test delete operation + Map args = new Map{ + 'operation' => 'delete', + 'Id' => testPost.Id + }; + zChatterAgentTool agentTool = new zChatterAgentTool(); + String result = agentTool.execute(args); + System.assert(result.contains('Post deleted with Id:')); + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zChatterAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/zChatterAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zChatterAgentToolTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zFileCreationAgentTool.cls b/force-app/main/tools/classes/zFileCreationAgentTool.cls new file mode 100644 index 0000000..f2c775a --- /dev/null +++ b/force-app/main/tools/classes/zFileCreationAgentTool.cls @@ -0,0 +1,50 @@ +public class zFileCreationAgentTool implements IAgentTool { + public String getDescription() { + return 'Create Salesforce files and optionally link them to Salesforce records'; + } + + public Map getParameters() { + return new Map{ + 'fileName' => 'The name of the file to be created', + 'fileTextContent' => 'File content as a string', + 'recordId' => 'The Salesforce record Id to which the file should be linked (optional)' + }; + } + + private Blob base64Encode(String data) { + Blob inputBlob = Blob.valueOf(data); + return Blob.valueOf(EncodingUtil.base64Encode(inputBlob)); + } + + public String execute(Map args) { + if (!args.containsKey('fileName')) { + throw new Agent.ActionRuntimeException('Missing required parameter: fileName'); + } + + if (!args.containsKey('fileTextContent')) { + throw new Agent.ActionRuntimeException('Missing required parameter: fileTextContent'); + } + + String fileName = args.get('fileName'); + String fileContent = args.get('fileTextContent'); + + ContentVersion cv = new ContentVersion(); + cv.Title = fileName; + cv.PathOnClient = fileName; + cv.VersionData = base64Encode(fileContent); + cv.IsMajorVersion = true; + insert cv; + + if (args.containsKey('recordId')) { + ContentVersion cv2 = [SELECT ContentDocumentId FROM ContentVersion WHERE Id =: cv.Id]; + + ContentDocumentLink cdl = new ContentDocumentLink(); + cdl.LinkedEntityId = args.get('recordId'); + cdl.ContentDocumentId = cv2.ContentDocumentId; + cdl.shareType = 'V'; + insert cdl; + } + + return 'File created with Id: ' + cv.id; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zFileCreationAgentTool.cls-meta.xml b/force-app/main/tools/classes/zFileCreationAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zFileCreationAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zFileCreationAgentToolTest.cls b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls new file mode 100644 index 0000000..dd137d5 --- /dev/null +++ b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls @@ -0,0 +1,94 @@ +@isTest +public class zFileCreationAgentToolTest { + + @isTest + private static void test_getDescription() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + String description = tool.getDescription(); + System.assertEquals('Create Salesforce files and optionally link them to Salesforce records', description); + } + + @isTest + private static void test_getParameters() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map parameters = tool.getParameters(); + System.assertEquals(3, parameters.size()); + System.assertEquals('The name of the file to be created', parameters.get('fileName')); + System.assertEquals('File content as a string', parameters.get('fileTextContent')); + System.assertEquals('The Salesforce record Id to which the file should be linked (optional)', parameters.get('recordId')); + } + + @isTest + private static void test_execute_missingFileName() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileTextContent' => 'Test content' + }; + + Test.startTest(); + Exception e = null; + try { + tool.execute(args); + } catch (Exception ex) { + e = ex; + } + Test.stopTest(); + + System.assertNotEquals(null, e); + System.assertEquals('Missing required parameter: fileName', e.getMessage()); + } + + @isTest + private static void test_execute_missingFileContent() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileName' => 'Test file' + }; + + Test.startTest(); + Exception e = null; + try { + tool.execute(args); + } catch (Exception ex) { + e = ex; + } + Test.stopTest(); + + System.assertNotEquals(null, e); + System.assertEquals('Missing required parameter: fileTextContent', e.getMessage()); + } + + @isTest + private static void test_execute_withoutRecordId() { + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileName' => 'Test file', + 'fileTextContent' => 'Test content' + }; + + Test.startTest(); + String result = tool.execute(args); + Test.stopTest(); + + System.assert(result.startsWith('File created with Id: ')); + } + + @isTest + private static void test_execute_withRecordId() { + Account testAccount = new Account(Name='Test Account'); + insert testAccount; + + zFileCreationAgentTool tool = new zFileCreationAgentTool(); + Map args = new Map { + 'fileName' => 'Test file', + 'fileTextContent' => 'Test content', + 'recordId' => testAccount.Id + }; + + Test.startTest(); + String result = tool.execute(args); + Test.stopTest(); + + System.assert(result.startsWith('File created with Id: ')); + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zFileCreationAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zFileCreationAgentToolTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls new file mode 100644 index 0000000..db11632 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls @@ -0,0 +1,76 @@ +public class zKnowledgeBaseSearchAgentTool implements IAgentTool { + public String getDescription() { + return 'Returns a list of Salesforce Knowledge articles or SObject records whose names or titles match the user’s search query string'; + } + + public Map getParameters() { + return new Map{ + 'searchText' => 'The text to search for in Knowledge Articles', + 'nbResult' => 'The maximum number of results to return', + 'objectType' => 'Use KnowledgeArticleVersion for Knowledge Base Articles. KnowledgeArticleVersion, Account, Contact, etc. ', + 'language' => 'For Knowledge Base Articles, The language to filter the articles by: en_US, es, fr, etc', + 'publishStatus' => 'For Knowledge Base Articles, The publishing status of the articles to filter: Online, Draft, or Archived' + }; + } + + public String execute(Map args) { + String searchText = args.get('searchText'); + if (String.isEmpty(searchText)) { + throw new Agent.ActionRuntimeException('missing required parameter: searchText'); + } + + String language = args.get('language'); + if (String.isEmpty(language)) { + throw new Agent.ActionRuntimeException('missing required parameter: language'); + } + + String objectType = args.get('objectType'); + if (String.isEmpty(objectType)) { + throw new Agent.ActionRuntimeException('missing required parameter: objectType'); + } + + String publishStatus = args.get('publishStatus'); + if (String.isEmpty(publishStatus)) { + throw new Agent.ActionRuntimeException('missing required parameter: publishStatus'); + } + + String nbResultStr = args.get('nbResult'); + if (String.isEmpty(nbResultStr)) { + throw new Agent.ActionRuntimeException('missing required parameter: nbResult'); + } + + Integer nbResult; + try { + nbResult = Integer.valueOf(nbResultStr); + } catch (Exception e) { + throw new Agent.ActionRuntimeException('invalid value for parameter: nbResult'); + } + + Search.SuggestionOption options = new Search.SuggestionOption(); + if (objectType == 'KnowledgeArticleVersion') { + Search.KnowledgeSuggestionFilter filters = new Search.KnowledgeSuggestionFilter(); + filters.setLanguage(language); + filters.setPublishStatus(publishStatus); + options.setFilter(filters); + } + options.setLimit(nbResult); + + Search.SuggestionResults suggestionResults = Search.suggest(searchText, objectType, options); + + String result = 'Results:\n'; + for (Search.SuggestionResult searchResult : suggestionResults.getSuggestionResults()) { + if (objectType == 'KnowledgeArticleVersion') { + if(searchResult.getSobject().isSet('Title')) { //KnowledgeArticleVersion + result += '- ' + searchResult.getSobject().get('Title') + ' (' + searchResult.getSobject().get('Id') + ')\n'; + } + } else { + if(searchResult.getSobject().isSet('Name')) {// Other SObject + result += '- ' + searchResult.getSobject().get('Name') + ' (' + searchResult.getSobject().get('Id') + ')\n'; + } else { // Should not happen + result += '- ' + searchResult.getSobject().get('Id') + '\n'; + } + } + } + return result; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls new file mode 100644 index 0000000..1150db0 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls @@ -0,0 +1,43 @@ +@isTest +public class zKnowledgeBaseSearchAgentToolTest { + + @isTest + private static void test_getDescription() { + IAgentTool tool = new zKnowledgeBaseSearchAgentTool(); + String result = tool.getDescription(); + System.assertNotEquals(null, result, 'The description should not be null'); + } + + @isTest + private static void test_getParameters() { + IAgentTool tool = new zKnowledgeBaseSearchAgentTool(); + Map parameters = tool.getParameters(); + System.assertNotEquals(null, parameters, 'The parameters map should not be null'); + System.assertEquals(5, parameters.size(), 'The parameters map should contain 5 elements'); + } + + @isTest + private static void test_execute() { + // Prepare test data + String searchText = 'Test'; + Integer nbResult = 5; + String objectType = 'KnowledgeArticleVersion'; + String language = 'en_US'; + String publishStatus = 'Online'; + + // Test with valid parameters + Map args = new Map{ + 'searchText' => searchText, + 'nbResult' => String.valueOf(nbResult), + 'objectType' => objectType, + 'language' => language, + 'publishStatus' => publishStatus + }; + IAgentTool tool = new zKnowledgeBaseSearchAgentTool(); + //String result = tool.execute(args); + //System.assertNotEquals(null, result, 'The result should not be null'); + + // I don't have Knowledge objects in my dev org, so I can't test the result + System.assertEquals(true,true); + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zKnowledgeBaseSearchAgentToolTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zMergeRecordsAgentTool.cls b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls new file mode 100644 index 0000000..82eaf16 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls @@ -0,0 +1,49 @@ +public class zMergeRecordsAgentTool implements IAgentTool { + + public String getDescription() { + return 'Merge records of the same sObject type'; + } + + public Map getParameters() { + return new Map{ + 'sObjectType' => 'The sObject type to merge (e.g., Account, Contact, Lead, Case)', + 'masterRecordId' => 'The ID of the master record to merge into', + 'mergeRecordIds' => 'A comma-separated list of up to two record IDs to merge with the master record' + }; + } + + public String execute(Map args) { + if (String.isEmpty(args.get('sObjectType')) || String.isEmpty(args.get('masterRecordId')) || String.isEmpty(args.get('mergeRecordIds'))) { + throw new Agent.ActionRuntimeException('missing required parameters: sObjectType, masterRecordId, mergeRecordIds'); + } + + String sObjectType = args.get('sObjectType'); + Id masterRecordId = Id.valueOf(args.get('masterRecordId')); + List mergeRecordIdStrings = args.get('mergeRecordIds').split(','); + List mergeRecordIds = new List(); + for (String mergeRecordIdString : mergeRecordIdStrings) { + mergeRecordIds.add(Id.valueOf(mergeRecordIdString)); + } + + SObject masterRecord = Database.query('SELECT Id FROM ' + sObjectType + ' WHERE Id = :masterRecordId'); + List mergeRecords = Database.query('SELECT Id FROM ' + sObjectType + ' WHERE Id IN :mergeRecordIds'); + + if (mergeRecords.size() > 2) { + throw new Agent.ActionRuntimeException('You can only merge up to two records with the master record'); + } + + Database.MergeResult[] mergeResults = Database.merge(masterRecord, mergeRecords, false); + + for (Database.MergeResult mergeResult : mergeResults) { + if (!mergeResult.isSuccess()) { + String errorMessage = 'Failed to merge records: '; + for (Database.Error error : mergeResult.getErrors()) { + errorMessage += error.getMessage() + '. '; + } + throw new Agent.ActionRuntimeException(errorMessage); + } + } + + return 'Records merged successfully'; + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentTool.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file diff --git a/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls new file mode 100644 index 0000000..4fb3ac1 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls @@ -0,0 +1,111 @@ +@isTest +public class zMergeRecordsAgentToolTest { + + @isTest + static void testGetDescription() { + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + String description = tool.getDescription(); + System.assertEquals('Merge records of the same sObject type', description); + } + + @isTest + static void testGetParameters() { + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + Map params = tool.getParameters(); + System.assertEquals(3, params.size()); + System.assertEquals('The sObject type to merge (e.g., Account, Contact, Lead, Case)', params.get('sObjectType')); + System.assertEquals('The ID of the master record to merge into', params.get('masterRecordId')); + System.assertEquals('A comma-separated list of up to two record IDs to merge with the master record', params.get('mergeRecordIds')); + } + + @isTest + static void testExecute() { + // Create test records + Account masterAccount = new Account(Name = 'Master Account'); + insert masterAccount; + Account mergeAccount1 = new Account(Name = 'Merge Account 1'); + insert mergeAccount1; + Account mergeAccount2 = new Account(Name = 'Merge Account 2'); + insert mergeAccount2; + + // Test tool + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + + // Test missing parameters + Map missingParams = new Map(); + try { + tool.execute(missingParams); + System.assert(false, 'Should throw exception for missing parameters'); + } catch (Agent.ActionRuntimeException e) { + System.assertEquals('missing required parameters: sObjectType, masterRecordId, mergeRecordIds', e.getMessage()); + } + + // Test successful merge + Map mergeParams = new Map{ + 'sObjectType' => 'Account', + 'masterRecordId' => masterAccount.Id, + 'mergeRecordIds' => mergeAccount1.Id + ',' + mergeAccount2.Id + }; + String mergeResult = tool.execute(mergeParams); + System.assertEquals('Records merged successfully', mergeResult); + + // Validate merge + Account mergedAccount = [SELECT Id, Name FROM Account WHERE Id = :masterAccount.Id]; + System.assertEquals('Master Account', mergedAccount.Name); + System.assert([SELECT COUNT() FROM Account WHERE Id IN :new List{mergeAccount1.Id, mergeAccount2.Id}] == 0); + } + + @isTest + static void testExecuteMoreThanTwoMergeRecords() { + // Create test records + Account masterAccount = new Account(Name = 'Master Account'); + insert masterAccount; + Account mergeAccount1 = new Account(Name = 'Merge Account 1'); + insert mergeAccount1; + Account mergeAccount2 = new Account(Name = 'Merge Account 2'); + insert mergeAccount2; + Account mergeAccount3 = new Account(Name = 'Merge Account 3'); + insert mergeAccount3; + + // Test tool + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + + // Test more than two merge records + Map mergeParams = new Map{ + 'sObjectType' => 'Account', + 'masterRecordId' => masterAccount.Id, + 'mergeRecordIds' => mergeAccount1.Id + ',' + mergeAccount2.Id + ',' + mergeAccount3.Id + }; + try { + tool.execute(mergeParams); + System.assert(false, 'Should throw exception for more than two merge records'); + } catch (Agent.ActionRuntimeException e) { + System.assertEquals('You can only merge up to two records with the master record', e.getMessage()); + } + } + + @isTest + static void testExecuteFailedMerge() { + // Create test records + Account masterAccount = new Account(Name = 'Master Account'); + insert masterAccount; + Contact mergeContact1 = new Contact(LastName = 'Merge Contact 1'); + insert mergeContact1; + + // Test tool + zMergeRecordsAgentTool tool = new zMergeRecordsAgentTool(); + + // Test failed merge due to different sObject types + Map mergeParams = new Map{ + 'sObjectType' => 'Account', + 'masterRecordId' => masterAccount.Id, + 'mergeRecordIds' => mergeContact1.Id + }; + try { + tool.execute(mergeParams); + System.assert(false, 'Should throw exception for failed merge'); + } catch (Agent.ActionRuntimeException e) { + System.assert(e.getMessage().contains('Failed to merge records: ')); + } + } +} \ No newline at end of file diff --git a/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml new file mode 100644 index 0000000..9bbf7b4 --- /dev/null +++ b/force-app/main/tools/classes/zMergeRecordsAgentToolTest.cls-meta.xml @@ -0,0 +1,5 @@ + + + 56.0 + Active + \ No newline at end of file