• huskerwendy
  • NEWBIE
  • 110 Points
  • Member since 2010

  • Chatter
    Feed
  • 3
    Best Answers
  • 0
    Likes Received
  • 0
    Likes Given
  • 64
    Questions
  • 104
    Replies
I need help determining the logic to use in my flow. Basically, I want to call a flow from process builder that will create new records based on the value passed in from the process builder. We have a custom obejct (transaction) and a new records is created, if the frequency of the parent object of the transaction is "Annual", I need the flow to create 11 additional records with the date for each record equal to the first day of the next 11 months. If the frequency is "Quarterly", I need the flow to create 2 additional records with date equal to the first day of the next two months. If the Frequency is "Semiannual", I need the flow to create 5 additional records with the date of each one equal to the first day of the next 5 months. 

Is this somethig flow can do? My plan was to create a counter based on the frequency and then loop until the frequency counter is reached. However, I can't seem to figure out how to loop through anything other then a Salesforce object. However in this case the objects don't exist yet. 
I found this app on the appexchange that will validate if there is a primary contact on the opportunity. However, I also need to know if the primary contact has changed. This is a link to the app:
https://appexchange.salesforce.com/listingDetail?listingId=a0N300000025Vs1EAE

I'm trying to modify the code but am getting an error.
trigger updatecontactrolecount on Opportunity (before insert, before update){
Boolean isPrimary;
Integer iCount;
Boolean isPrimaryChanged;

Map<String, Opportunity> oppty_con = new Map<String, Opportunity>();//check if the contact role is needed and add it to the oppty_con map
for (Integer i = 0; i < Trigger.new.size(); i++) 
{
        oppty_con.put(Trigger.new[i].id,
        Trigger.new[i]);      
}
    
isPrimary = False; 
isPrimaryChanged = False;
for (list<OpportunityContactRole> oppcntctrle :[select OpportunityId, ContactID from OpportunityContactRole where (OpportunityContactRole.IsPrimary = True and OpportunityContactRole.OpportunityId in :oppty_con.keySet())]){
    if (oppcntctrle .Size() >0) {
         isPrimary = True; 
        //for (Opportunity o : trigger.new){
            //OpportunityContactRole contactRole =[select ContactID from OpportunityContactRole where IsPrimary = true and OpportunityId = :oppcntctrle.id];   
            for (list<OpportunityContactRole> oldContactRole :[select OpportunityID, ContactID from OpportunityContactRole where OpportunityContactRole.IsPrimary = True and OpportunityId IN :Trigger.oldMap.keySet()]){               
                if(oldContactRole.ID != oppcntctrle.ContactID){      
                    isPrimaryChanged = true;
                }           
               }    
        //}
    }     
}

iCount = 0;
for (List<OpportunityContactRole> oppcntctrle2 : [select OpportunityId from OpportunityContactRole where (OpportunityContactRole.OpportunityId in :oppty_con.keySet())])//Query for Contact Roles
{    
 if (oppcntctrle2 .Size()>0)
 {
 iCount= oppcntctrle2 .Size();     
 }
}
for (Opportunity Oppty : system.trigger.new) //Check if  roles exist in the map or contact role isn't required 
{
Oppty.Number_of_Contacts_Roles_Assigned__c = iCount;
Oppty.Primary_Contact_Assigned__c =isPrimary; 
Oppty.Primary_Contact_Changed__c= isPrimaryChanged;
}
}
I'm getting an error (Initial term of field expression must be a concrete SObject: List) on line 21  if(oldContactRole.ID != oppcntctrle.ContactID){  

What am I doing wrong?  
 
When on an opportunity and we click the Add Product link, the "Create Opportunity Product" dialog box opens. When I type the product name in the "Product" field and click the search icon, it opens up an error page "Unfortunately, there was a problem. Please try agein. If the problem continues....." then I close it and get another error dialog that has an Error ID. The error is a number (which is never the same) with another number in parentheses. The number in parantheses is (-2068692419). Is anyone else experiencing this?

 

Error ID: 1557705666-6873 (-2068692419)
I've been told that I can parse the subject line of a case using flow and process builder but I really have no idea where to start. Can someone give me an outline of the steps I would take? I've done some investigating in flow but the only thing I can see that may work would be to use a loop variable but I don't know if I'm even heading in the right direction. 

Here's what I'm hoping to accomplish: 
We have cases that all come in from the same email address. The email address is not associated with any of the contacts on the accounts however they have the correct account number in the subject line of the case. I need to assign the case to the correct account based on the account number in the case subject line. All of the account numbers are six characters long. 

Here's an example of what the subject line would look like: "123456 Backups complete on "
I've been told that I can parse the subject line of a case using flow and process builder but I really have no idea where to start. Can someone give me an outline of the steps I would take? I've done some investigating in flow but the only thing I can see that may work would be to use a loop variable but I don't know if I'm even heading in the right direction. 

Here's what I'm hoping to accomplish:
We have cases that all come in from the same email address. The email address is not associated with any of the contacts on the accounts however they have the correct account number in the subject line of the case. I need to assign the case to the correct account based on the account number in the case subject line. All of the account numbers are six characters long. 

Here's an example of what the subject line would look like: "123456 Backups complete on "
 
I'm an admin trying to be a devleloper and am struggling. I'm trying to bulkify my trigger but am not sure how to assign multiple values from an aggregate query to a list. I've tried using a set, map and list but every example I see just has a Key and one value. I have two keys and multiple values.

My end goal is to update the case with the totalRevenue, TotalHours, and OverageHours from the billing. I have a related list of billing for each case. Each billing has a product that can have a different incident charge, per incident hours and possibly overage charge and each case can have multiple billings for the same product BUT only one case is counted as an incident. So if there are 4 billings with two different products, the incident charge would only be there once for each product, not four times for each billing. I wrote an aggregate query to get the sum of hours worked for each case and product. What I need to happen is for my trigger to loop through the aggregate results and for each case the for each product:

for case
loop through each product
if the totalHoursWorked > Per_Incident_hours__c then
total_hours =  (totalHoursWorked - incidentHours * overageCharge) + incidentCharge 
else total_hours = totalHoursWorked * incidentCharge
get next product
then update case TotalRevenue, TotalHours, TotalOverageHours
get next case

Here's what I have. However I don't know what to do with the AggregateResult set. 
trigger CaseClosed on Case (after insert, after update) {
    // this code will get the list of closed cases for Cloud IT records. It will loop through the billing for each case 
    // and calculate the total case revenue along with the Total Hours Worked and Case Overage Hours. 
    // list to hold updated case values
    List<Case> updateCase = new List<Case>();
    
   // get list of closed cases and add the case to the case list
   	set<id> caseIDs = new set<id>();
    for (Case c : trigger.new){
        	if (c.IsClosed && c.RecordTypeId == '012600000001COh') {
               	caseIDs.add(c.Id); 
                  system.debug('in CaseClosed trigger');
        	}
        } 
    
    // loop through the caseIDs and get billing for each product
    // create an aggregate Map of all billing for each case by product
    LIST<aggregateResult> results = ([SELECT Case__c, Product__c, MAX(Per_Incident_Hours__c) incidentHours, MAX(Incident_Charge__c) incidentCharge, MAX(Overage_Amount__c) overageCharge, SUM(Hours_Worked__c) totalHoursWorked FROM Billing__c  WHERE Case__c in : caseIds GROUP BY Case__c, Product__c]);  
    decimal total_hours = 0;
    decimal total_dollars = 0;
    decimal total_overage_hours = 0;
    
    // create a map to hold results from query
    Map<Id, ID> arCaseProduct = new Map<Id, Id>();
   list<Object> myList = new list<Object>();
    // loop through and get billing
    for (AggregateResult ar : results){
    	System.debug('in aggregate debug'+ar.get('Case__c')+'-'+ar.get('Product__c')+'-'+ar.get('incidentHours')+'-'+ar.get('incidentCharge')+'-'+ar.get('overageCharge')+'-'+ar.get('totalHoursWorked'));  
    	arCaseProduct.put((ID)ar.get('Case__c'), (id)ar.get('Product__c'));
        system.debug('arCaseProduct is '+ arCaseProduct);
    }
}



 
I'm trying to create a report where I need to sum the previous group values which is a fomula field. I'm trying to use PREVGROUP function and plugin the formula field name, but it says it's an invalid field.

My end goals is to create a report of revenue for each case (which is an incident) based on the billing records and the product on the billing record. One case can have many billing records and each billing record has one product (lookup to the Product object). I need to sum up the revenue based on the product from the billing because each product can have a different incident rate. I'm not really sure how to sum these up at each level.

The formula for the BillingProductRevenue field is:
(FK_Product2.Per_Incident_Hours__c:MAX*FK_Product2.Per_Incident_Rate__c:MAX) + ((Billing__c.Hours_Worked__c:SUM-FK_Product2.Per_Incident_Hours__c:MAX) *FK_Product2.Per_Incident_Overage_Rate__c:MAX)

Here's my report. for the first record at the case level, the total Revenue should be 174 + 116.50=290.50. That value should be at the account level as well since there is only one case. However, if there were two cases, I need it to sum up the revenue from both cases. Is this possible in the report? 

User-added image

 
I've turned on duplicate alerts but need them to not run for Web to Lead forms. I've created a couple of duplicate rules but they don't seem to be working. The lead is not created and I get an email notifying me that the lead was not created because it's a duplicate. My user is the user that creates Web To Lead records and I'm the Sys Admin. I've created a couple of rules - one where the duplicate rule won't run if the

Current User: Profile is System Administrator
or
Current user: Username = is my emailaddress
or
Lead: Created By = my username.

I also followed instructions in this article for the other rule:
https://help.salesforce.com/HTViewSolution?id=000212677&language=en_US

Neither seem to be working. What am I doing wrong?
On our public Knowledge site, we created our own design with our own CSS which is responsive so we don't need the mobile site that comes with the app. However when you go to our site on a mobile device, it redirects to the pkb_mobile app. I've done the opposite of enabling it by following the instructions (page 12) of the install guide but it still redirects. https://appexchange.salesforce.com/servlet/servlet.FileDownload?file=00P3000000HCTKdEAP

On a mobile device, if you go to:
project-firespring.cs17.force.com/printerpresence
it will redirect to
project-firespring.cs17.force.com/printerpresence /pkb_mobile
How do I turn that off?
 
My company is looking for a devloper to integrate the GoToWebinar and GoToWebcast import with Salesforce using the REST API. Let me know if you are interested in consulting work.

Thanks!
Wendy 
I'm not really a developer but have used apex in the past to write triggers. Now I'm trying to use the Rest API to make a call to GoToWebinar's API. I've written some code but am not sure how to test to see if my API call is even working. How do a test that from the Developer Console? Also, when I implement the feature, I am hoping to have it execute without human interaction as a job that runs each night. How do you do that?

Here's my code:
public class g2wCallout {
    public void getWebinars(){
      HttpRequest req = new HttpRequest(); 
      //Set HTTPRequest Method
      req.setMethod('GET');
    
      //Set HTTPRequest header properties
      req.setHeader('content-type', 'application/json');
      req.setHeader('Accept','application/json');
      req.setHeader('Authorization','OAuth ');
     
      req.setEndpoint( 'https://api.citrixonline.com/G2W/rest/organizers/3131084/historicalWebinars?fromTime=2015-05-28T18:00:00Z&toTime=2015-05-28T24:00:00Z' );
    
      //Set the HTTPRequest body	
       req.setBody('{"access_token":"blahblahblahblahblah"}'); 	
    
      Http http = new Http();
      
       try {
     
            //Execute web service call here		
           // HTTPResponse res = http.send(req);	
    
            //Helpful debug messages
             System.debug('this is a test');
            /*System.debug(res.toString());
          
            System.debug('STATUS:'+res.getStatus());
            System.debug('STATUS_CODE:'+res.getStatusCode());
            */
        } catch(System.CalloutException e) {
        //Exception handling goes here....
        }	
	}
}

 
I'm trying to deploy Public Knowledge to our production instance from the Sandbox. I'm receiving an error on live that I'm not getting in the Sandbox and I dont' know what's causing the error. The Business Hours are set up the same between the Sandbox and Production. I'm not really sure what is causing the error or how to fix it. Can someone please help? Thanks!

This is the error:
pkb_mobile_Test.test_MobilePhoneCall(), Details: System.AssertException: Assertion Failed: Expected: true, Actual: false Class.pkb_mobile_Test.test_MobilePhoneCall: line 843, column 1

here's the code from the pkb_mobile_Test.apxc class that is causing the error:
@isTest(SeeAllData=true)
    static void test_MobilePhoneCall(){
       PKB__c pkS = populateSetup();
  	   BusinessHours bH = [Select Id from BusinessHours where IsDefault = true limit 1];

       DateTime timeToSend = businesshours.addGmt(bH.id, system.now(), 1000 * 60);
       map<String,String> resp = (map<String,String>) pkb_mobile_controller.getPhoneCallAvailable(timeToSend);
    	  system.assertEquals( 'true', resp.get('available') );

    }


    public static PKB__c populateSetup() {
        // create custom settings collection based on siteName
        PKB__c pkb = new PKB__c();
        pkb.Name = siteName;
        pkb.MCategory_Group_1__c = 'group1';
        pkb.MCategory_Group_2__c = 'group2';
        pkb.MCategory_Group_3__c = 'group3';
        pkb.MRoot_Category_1__c = 'root1';
        pkb.MRoot_Category_2__c = 'root2';
        pkb.MRoot_Category_3__c = 'root3';

        pkb.Create_Contact_and_Account__c = false;
        pkb.Contact_Us_Available__c = false;
        pkb.Display_Article_Summary__c = true;
        pkb.Multi_Language_Enabled__c = true;
        pkb.Popular_Articles_Size__c = 2;
        pkb.Related_Articles_Size__c = 2;
        pkb.Results_Page_Size__c = 2;
        pkb.Selected_Languages__c = 'en_US';
        pkb.MEnableCall__c = true;
        pkb.MBusinessHours__c = 'testPkbMT';
        pkb.MPhoneNumber__c = '8774478936';

        insert pkb;
        if (kavObj != null){

            //insert records on the KAV fields custom setting
            Id kavID = String.valueOf(kavObj.get('id'));
            Schema.SObjectType token = kavID.getSObjectType();
            Schema.DescribeSObjectResult dr = token.getDescribe();
            set<String> allFields = token.getDescribe().fields.getMap().keySet();
            list<String> listFields = new list<String>();
            listFields.addAll(allFields);
            String layout = String.join(listFields,',');
            Integer cutAt = layout.lastIndexOf(',', 50);
            pkb_Ka__c pkF = new pkb_Ka__c();
            pkF.layout__c = layout.substring(0,cutAt);
            pkF.apiName__c  =  objType;
            pkF.pkb__c = pkb.Id;
            pkF.Name ='RAMDOM_UNUSED_NAME';
            insert pkF;
        }


        system.debug(logginglevel.INFO,'\n\n\n=======\n pkb_mobile_Test populateSetup ['+siteName+'] \n >>>Contact_Us_Available__c : '+pkb.Contact_Us_Available__c);

        return pkb;
    }

Here is the Controller code that the test class is using
//Bussines hours / call available
    public static Object getPhoneCallAvailable(DateTime d){
        map<String,String> ret = new map<String,String>();

        pkb_mobile_proxy.ResponseItem r = pkb_mobile_controller.getCurrentSiteSetUp();
        String businessHour = r.setup.get('businessHours');
        if ( Test.isRunningTest() ) businessHour = pkb_mobile_Test.getTestBusinessHourName();

        Boolean isCallEnabled =  pkb_mobile_controller.isPhoneCallAvailable( d,  businessHour);

        if (isCallEnabled){
             if ( r.setup.get('phoneNumber') != null ){
                ret.put('available',String.valueOf(true));
                ret.put('number',r.setup.get('phoneNumber'));
            }else{
                ret.put('available',String.valueOf(false));
            }
        }else{
            ret.put('available',String.valueOf(false));
        }
        return ret;
    }

 
I have a trigger that I can't get code coverage on an if statment. What am i doing wrong. 
I can't get code coverage on line 33 "if (a.AccountTeamMembers == Null || a.AccountTeamMembers.isEmpty()

Here's the trigger:
trigger trgAsset on Asset (after insert, after update, after delete) {
	if (trigger.isInsert || trigger.isUpdate){
		/*If the Asset has VersaDoc and the account doesn't have a VersaDoc Project Account Team Member, 
		  it will assign the next VersaDoc Project manager from the assignment groups to the Account Team*/

        Set<id> accountTeamAccountIds = new Set<id>(); // set of accountIDs that have VersaDoc in the asset
	    for (Asset a : Trigger.new){  
	    	if (a.HasVersadoc__c == 1 || a.HasVersadocStudio__c == 1 ) {
        		accountTeamAccountIds.add(a.AccountId); 
       	 	} 	
	    }
        
		list<Assignment_Group_Name__c> asgnGroupNameIDs = [SELECT Id FROM Assignment_Group_Name__c WHERE Name = 'Support - VersaDoc Project Managers' limit 1];
		system.debug('asgnGroupnameIDs is ' + asgnGroupNameIDs);
	
		Assignment_Groups__c[] asgnGroups = new List<Assignment_Groups__c>([SELECT Group_Name__c, User__c, Last_Assignment__c, Millisecond__c 
                                   FROM Assignment_Groups__c 
                                   WHERE Group_Name__c in :asgnGroupNameIds
                                   AND Active__c = 'True' AND User_Active__c = 'True'
                                   ORDER BY Last_Assignment__c, Millisecond__c] );                                    
	
		Integer groupCount = asgnGroups.size();
	
    	System.debug('>>>>>asgnGroups: '+asgnGroups);   
   		if (asgnGroups.isEmpty()) return;                      

		//loop through list of accounts and get the accounts w/o VersaDoc Project Manager
		AccountTeamMember[] NewMembers = new AccountTeamMember[]{};  //list of new team members to add
	    AccountShare[] newShare = new AccountShare[]{};  //list of new shares to add
		Map<id, Account> acctsToUpdate = new Map<id, Account>([Select a.Id, (Select Id, AccountId From AccountTeamMembers WHERE TeamMemberRole = 'VersaDoc Project Manager' limit 1) From Account a Where a.Id in :accountTeamAccountIds]);
		Integer cnt = 0;
	    for (Account a : acctsToUpdate.values()){
	    	if (a.AccountTeamMembers == null || a.AccountTeamMembers.isEmpty()) {
	    		AccountTeamMember TeamMemberAd=new AccountTeamMember();
		        TeamMemberAd.AccountId=a.id;
		        TeamMemberAd.UserId=asgnGroups[cnt].User__c;
		       	TeamMemberAd.TeamMemberRole = 'VersaDoc Project Manager';
		        NewMembers.add(TeamMemberAd);	
		        datetime now = datetime.now();
		        asgnGroups.get(cnt).Last_Assignment__c=now;
		        asgnGroups.get(cnt).Millisecond__c = now.millisecondGMT(); 
	    		cnt ++;
	    		if (cnt == groupCount){ cnt = 0;}    	
	    	}
	    } 

		//insert any valid members then add their share entry if they were successfully added
	    Database.SaveResult[] lsr = Database.insert(NewMembers,false);
		Integer newcnt=0;
	    for(Database.SaveResult sr:lsr){
			if(!sr.isSuccess()){
				Database.Error emsg = sr.getErrors()[0];
				system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg);
			}else{
				newShare.add(new AccountShare(UserOrGroupId=NewMembers[newcnt].UserId, AccountId=NewMembers[newcnt].Accountid, AccountAccessLevel='Edit',OpportunityAccessLevel='Edit'));
			}
				newcnt++;			
	    }
	    //insert the new shares
	    Database.SaveResult[] lsr0 =Database.insert(newShare,false); 
	    Integer newcnt0=0;
	    for(Database.SaveResult sr0:lsr0){
			if(!sr0.isSuccess()){
				Database.Error emsg0=sr0.getErrors()[0];
			    system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0);
			}
				newcnt0++;
	    } 
	    // update assignment groups with their LastAssignmentDate
	    update asgnGroups; 	  
    }
}
Heres' the test class
@isTest(SeeAllData=false)
private class testTrgAssetVersaDocTeamAssignment {
    static testMethod void myUnitTest() {
        // create user to run the test a
        User u =  TestDataFactory.createTestRunAsUser('Standard User', 'Sales Assistant');  
        
        System.runAs(u) {  
            // Switch to the runtime 
             Test.StartTest();
            	// TestDataFactory.createProduct('PrinterPresence Gold Level', 'VersaDoc');
                list<Account> printAccts = TestDataFactory.createTestAccounts(2, 'Printers', 'Client');
                system.debug('***** printAccts is ' + printAccts);
                performCreateAssignmentGroups(u.Id);   
                checkVersaDocAccountTeam(printAccts);
                performCreateVersaDocAssets(u.Id, printAccts);  
            Test.StopTest();   
         }
    }
    
    public static void performCreateAssignmentGroups(id createdby){
        Assignment_Group_Name__c agn = TestDataFactory.createAssignmentGroup('Support - VersaDoc Project Managers', 'Account');
        list<User> u = TestDataFactory.createMulitpleUsers(2, 'Standard User-Support VersaDoc', 'Product Support Rep');     
        system.debug('**** user list is' + u);
        TestDataFactory.addUsersToAssigmentGroup(u, agn);
    }   
    
    public static void checkVersaDocAccountTeam(list <Account> accts){
        Map<id, Account> acctsToCheck = new Map<id, Account>([Select a.Id, (Select Id, AccountId From AccountTeamMembers WHERE TeamMemberRole = 'VersaDoc Project Manager' limit 1) From Account a Where a.Id in :accts]);
        List<Id> acct = new list<Id>();
        System.debug('**** acctsToCheck is ' + acctsToCheck);
        for (Account a: acctsToCheck.values()){
            if (a.AccountTeamMembers == null || a.AccountTeamMembers.isEmpty()) {
				system.debug('**** in if statement if for loop ' + acctsToCheck.values());
                acct.add(a.Id);
        	}
        }
        system.assert(acct.size()>0);
    }
    
    public static void performCreateVersaDocAssets(id createdby, List <Account> accts){
        // add PrinterPresence Gold level Asset (Has VersaDoc)
        date now = date.today(); 
        list<Account> acct = [Select Id from Account where id =: accts];
        list<Asset> assts = new list<Asset>();        
        assts = TestDataFactory.createAssets(accts, now, 'PrinterPresence Gold Level', 'Purchased', 310.00, 7500.00);
        system.debug('***** assts is ' + assts);
        
        Map<id, Account> acctTeams = new map<id, Account>([Select a.Id, (Select Id, AccountId, TeamMemberRole From AccountTeamMembers WHERE TeamMemberRole = 'VersaDoc Project Manager' limit 1) From Account a Where a.Id  =:accts]);
        system.debug('**** acctTeams after adding assets is ' + acctTeams);
        for (Account a : acctTeams.values()){
        	if (a.AccountTeamMembers != null && a.AccountTeamMembers.IsEmpty()==false) {   
            System.assertNotEquals(a.AccountTeamMembers, Null);
            }
        } 
        System.assert(acct.size()>0);
    }
}


I have a trigger on assets that inserts records into a custom object dependent on the product family and if the value of some custom fields changes. The trigger works fine when I edit records in the user interface in Salesforce. However, I can't make the trigger fire from my test class. I'm not sure why. The "RMR__c" field is updated via a workflow rule on the asset when the "Num_Users_Devices__c" or "RMR_Per_Unit__c". The test class will never go into the "if (trigger.IsUpdate && ((a.Product2.Family == "Cloud IT'......for loop in the trigger.  I'm using a data factory to create the test data and passing in the Product Family but it seems as though the product family is empty in my test class. How can I see what the product family is for the asset?

Here's the Data Factory method to create the product.

public static void createProductWithFamily(String productName, String productFamily){
       // First, set up test price book entries. // Insert a test product.
    	Product2 prod = new Product2(Name = productName, Family = productFamily);
        insert prod;
          system.debug('**** in createProductWithFamily ' + prod);
        // Get standard price book ID.  // This is available irrespective of the state of SeeAllData.   
        Id pricebookId = Test.getStandardPricebookId();
 
        // Insert a price book entry for the standard price book. Standard price book entries require the standard price book ID we got earlier.
        PricebookEntry standardPrice = new PricebookEntry(Pricebook2Id = pricebookId, Product2Id = prod.Id, UnitPrice = 500, IsActive = true);
        insert standardPrice;
         // Create a custom price book
        Pricebook2 customPB = new Pricebook2(Name='Sales', isActive=true);
        insert customPB;
        // 2. Insert a price book entry with a custom price.
        PricebookEntry customPrice = new PricebookEntry(Pricebook2Id = customPB.Id, Product2Id = prod.Id,UnitPrice = 500, IsActive = true);
         insert customPrice; 
    }

Here's the trigger

trigger trgAsset on Asset (after insert, after update, after delete) {
	if (trigger.isInsert || trigger.isUpdate){
		/*If the asset is a Cloud it Product and the number of users changes, the trigger will insert a record into the Cloud_IT_Armor_Gain_Loss__c object with the armor gain or loss*/
		set<id> assetIds = new Set<id>(); // create a set of all asset ids to get the Product family
	    for (Asset a : Trigger.new){ 
	    	assetIds.add(a.Id);
	    }
        // create list of records to insert into Cloud_IT_Armor_Gain_lost object
       list<User_Device_ARMOR_Gain_Lost__c> insertRecords = new list<User_Device_ARMOR_Gain_Lost__c>();
        // loop through assets and get Id and product family
     	set<Asset> assts = new set<Asset>([Select Id, Product2.Family from Asset Where Id in :assetIds]);
       	system.debug('****** in trigger assts before for loop ' + assts);
 		//if trigger is update and product family = CloudIT or Floor 99 Legacy and old Armor is not equal to the new Armor and Old Num Users <> New Num Users
      	for (Asset a: assts){
          if (trigger.isUpdate && 
			((a.Product2.Family == 'Cloud IT' || a.product2.Family == 'Floor 99 Legacy') && (Trigger.oldMap.get(a.Id).RMR__c <> Trigger.newMap.get(a.Id).RMR__c)
 			&& ((Trigger.oldMap.get(a.Id).Num_Users_Devices__c <> Trigger.newMap.get(a.Id).Num_Users_Devices__c) || (Trigger.oldMap.get(a.Id).RMR_Per_Unit__c <> Trigger.newMap.get(a.Id).RMR_Per_Unit__c)))){
                    system.debug('**** in trigger asset in for loop is ' + a);
              Date ArmorDate = Date.Today();
              Id AsstID = a.Id;
              decimal PrevArmor =  Trigger.oldMap.get(a.Id).RMR__c;            
              decimal NewArmor = Trigger.newMap.get(a.Id).RMR__c;
              decimal Gain = 0;
              decimal Loss = 0;
              if (Trigger.newMap.get(a.Id).RMR__c > Trigger.oldMap.get(a.Id).RMR__c){
              	Gain = Trigger.newMap.get(a.Id).RMR__c -  Trigger.oldMap.get(a.Id).RMR__c;
              }else if (Trigger.newMap.get(a.Id).RMR__c < Trigger.oldMap.get(a.Id).RMR__c){
              	Loss = Trigger.oldMap.get(a.Id).RMR__c - Trigger.newMap.get(a.Id).RMR__c ;
              }                     
            User_Device_ARMOR_Gain_Lost__c c = new User_Device_ARMOR_Gain_Lost__c(
              	Asset__c = a.Id,
              	Armor_Date__c = ArmorDate,  
				Previous_Armor__c = PrevArmor,
				New_Armor__c = NewArmor,
              	Armor_Gain__c = Gain,
              	Armor_Lost__c = Loss);   
              insertRecords.add(c);
          }           
      	}
        
        system.debug('**** in trigger insertRecords is ' + insertRecords);
        // if the Num users or armor has changed insert the records
        if (insertRecords.size()>0){
           insert insertRecords; 
       } 	
    }		   
}

Here's the Test Class
/*test for the user/device ARMOR Gains/losses on assets */
@isTest(SeeAllData=false)
private class TestTrgAssetArmorGainsLoss {
    static testMethod void myUnitTest() {
            // create user to run the test a
            User u =  TestDataFactory.createTestRunAsUser('System Administrator', 'System Admin');  
            
            System.runAs(u) {  
            	// Switch to the runtime 
            	Test.StartTest();
             		TestDataFactory.createProductWithFamily('Base Cloud', 'Cloud IT');
               		list<Account> printAccts = TestDataFactory.createTestAccounts(2, 'Other', 'Client');    		
                 	list<Asset> asstCIT = TestDataFactory.createCloudITAssets(printAccts, date.today(), 'Base Cloud', 'Purchased', 10.00, 375, 10);
                	performUpdateAssetNumUsers(asstCIT);
                	checkUserArmorGainLost(asstCIT);
                Test.StopTest();   
             }
        }
	
    public static void performUpdateAssetNumUsers(list<Asset> asst){
        date now = date.today();
        system.debug('**** in performUpdateAssetNumUsers asset list is ' + asst);
        //update the number of users on the asset
        list<Asset>updateAsset = new list<Asset>();
        
		for (Asset ass : asst){
            system.debug('*** in performUpdateAssetNumUsers for loop ass is ' + ass);
            Asset ua = new Asset(
                id = ass.id,
                Num_Users_Devices__c = 12,
                RMR_Per_Unit__c = 10.00);
			updateAsset.add(ua);
       }   
        system.debug('**** in performUpdateAssetNumUsers after update' + updateAsset);
		update updateAsset;
    }
    
    public static void checkUserArmorGainLost(list<Asset> asst){
        //check results of assets to be sure the user/Device ARMOR Gains/Losses records was created.
		list <Asset> assts = [Select Id, RMR__c, Armor_date__c, Num_Users_Devices__c, Product2.Family from Asset Where Id =: asst];
   //     list<Product2> prod = [Select Id, Name, Family from Product2 where Id =: assts.Product2.Id];
   //     system.debug('**** in checkuserArmorGainLost prod is ' + prod);
         
        system.debug('***** assts after update is' + assts);
        list<Id> checkList = new list<id>();
        for (Asset a : assts){
            system.debug('**** asset a in for loop is ' + a);
            checkList.add(a.id);
        }
        set <User_Device_ARMOR_Gain_Lost__c> gainLost = new set<User_Device_ARMOR_Gain_Lost__c>([Select Id, Asset__c, Armor_date__c, Armor_Gain__c, Armor_Lost__c from User_Device_ARMOR_Gain_Lost__c /*Where Asset__c in: checkList */]);
        system.debug('***** gainLost is ' + gainLost);
	//	for (User_Device_ARMOR_Gain_Lost__c g : gainLost){
	//		System.assertEquals(now, g.Armor_date__c);   
	//	}  
        
    }   
}

I created a test class in API version 32 that is trying to query the Product2 to get the Product Name. It doesn't work unless I set SeeAllData=True. In my old classes, I can query the products table directly.

I thought that according to this we can set it to false again and still be able to get the products.
https://success.salesforce.com/ideaView?id=08730000000j9TpAAI

Here's my query. 
Product2 prod = [select Id, Name, Included_Components__c, HasVersadoc__c from Product2 where Name =: productName];

Why doesn't that work unless I set "SeeAllDate=True"? 


I'm having a hard time getting answer as to how to properly set up Public Knowledge when using multiple sites and categories. 

We have 3 main categories groups set up with sub categories in each. The main Categories are "Print and Sign", "Nonprofit" and "Small-Medium Business". Each category is assigned to a different site. We have some articles that are only assigned to the Nonprofit category. However, when you search on the site that's using the "Small-Medium Business" category and search using "No Filter", articles that only belong to the Nonprofit category are returned even though they don't belong to that category and specifically say "No Category" in Article Management for "Small-Medium Business".

I've tried editing the Visibility Settings to change from "All Categories" to Custom categories and that doesn't fix the problem. What am I missing? How can I restrict articles that are returned in searches with No filters? Is that the intended result when "No Filter" is selected?

Here are some images of how I have things set up:

here are the data categories. Each Category has children categories and all of them have "All" as the first subcategory.

User-added image

Data Category Visibility Settings:
User-added image

I have three sites. Each Site is set up to use a different Category and each site's profiles has data visibilty to a different category:

User-added image

Here's how an Article is set up and it's only category is "Nonprofit".
User-added image

When I go to the site for "Print and Sign" and do a search using "No Filter", it returns the article from above that is only assigned to the "Nonprofit" category.

User-added image

Can anyone help me figure out how to limit the search results to only articles that belong to a specific category? Do I need to set up the categories different? I've tried changing visibility settings and that seems to only cause the filter list to change (as in all of the sub categories are gone).
We've just purchased Knowledge and I'm in the process of setting it up and have some questions about Knowledge Articles as PDFs when attaching to cases:

1. Is it possible to style the PDF that is created from a case when using the merge field "Articles as PDFs"? If so, where do I find it?

2. The links to other Knowledge Articles don't work in the PDF that are attached to the email when the case. They work when you view the article on our site or in Article Management though.

3. Is there a way to include the Article in the actual email rather than as an attachement? We were able to do this with Solutions but I don't see any other merge fields available for Articles when I'm in the email template. It appears that the "Inline" checkbox that is available when your send an email with an attachment does nothing when it's checked. Any suggestions?

We're trying to customize Public Knowledge and prevent Salesforce from rendering it's own CSS using standardStylesheets="false". Here's the code on the we're using on the VisualForce page at the beginning of the page:

<apex:page cache="false"
  standardStylesheets="false"
  showHeader="false"
  sidebar="false"
  standardController="KnowledgeArticle"
  extensions="pkb_Controller"
  language="{!pkbCon.selectedLanguage}"
  applyBodyTag="false"
  applyHtmlTag="false"
  >
<html>


 

When I view the page source on the site, it seems to be ignoring the markup code on the Visualforce page and rendering it's own CSS. Are we using the correct code. Here's the code when I view the pagesource. How can we tell Salesforce not to display their CSS?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">

<html style="display:none !important;"><head><script src="/nonprofit/static/111213/js/perf/stub.js" type="text/javascript"></script><script src="/faces/a4j/g/3_3_3.Finalorg.ajax4jsf.javascript.AjaxScript?rel=1407535568000" type="text/javascript"></script><script src="/nonprofit/static/111213/js/functions.js" type="text/javascript"></script><script src="/nonprofit/jslibrary/1407441168000/sfdc/main.js" type="text/javascript"></script><script src="/nonprofit/jslibrary/jslabels/1407441168000/en_US.js" type="text/javascript"></script><script src="/nonprofit/static/111213/desktop/desktopAjax.js" type="text/javascript"></script><script src="/nonprofit/static/111213/js/picklist.js" type="text/javascript"></script><script src="/nonprofit/jslibrary/1400606638000/sfdc/VFState.js" type="text/javascript"></script><script src="/nonprofit/EXT/ext-3.3.3/ext.js" type="text/javascript"></script><script src="/nonprofit/jslibrary/1400606638000/sfdc/Knowledge.js" type="text/javascript"></script><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/zen-componentsCompatible.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/elements.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/common.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1405452552000/Theme3/gc/dStandard.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1407963638000/Theme3/00D600000006nRH/00560000002U8r0/gc/dCustom0.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/extended.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/setup.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/EXT/ext-3.3.3/resources/css/ext-all-notheme.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/ExtCSS-SFDC.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/knowledge.css" rel="stylesheet" type="text/css" /><link class="user" href="/nonprofit/sCSS/31.0/sprites/1406583088000/Theme3/default/gc/knowledgeHome.css" rel="stylesheet" type="text/css" /><script type="text/javascript">
//<![CDATA[
try{(function(){var w=self,l,p,o;if(w&&top){for(;w!==top&&(p=w.parent)&&p!==w&&(o=p.location)&&o.protocol===(l=w.location).protocol&&(o.host===l.host||(p.document&&p.document.domain===w.document.domain));w=p);if(w!==top)throw "";}({f:function(){document.documentElement?document.documentElement.style.display="":(!this.a&&(this.a=10),this.a<1E5&&(window.sfdcRetryShowWindow=this)&&setTimeout("sfdcRetryShowWindow.f()",this.a),this.a*=2)}}.f())})();}catch(e){if(top!==self)top.location=location;else throw e;}//]]></script></head>
<html>

I found this formula referenced by a few people:

https://help.salesforce.com/HTViewHelpDoc?id=formula_examples_dates.htm&language=en_US

I'm using it to find the business age between a custom date time field called First Contact Date and the Case Created Date. We want a 12 hour day starting at 7:00 AM. Everything works fine except when the date created is between midnight and 7:00 AM. When the date created is between those hours, the value returned in the formula is a negative number. How can I fix this? I created test datetime fields so that I can test the formula with different values. Here's the formula using the test fields. Any advice?

ROUND(12*(
(5*FLOOR((DATEVALUE(Test_First_Contact_Date__c)-DATE(1996,01,01))/7) +
MIN(5,
    MOD(DATEVALUE(Test_First_Contact_Date__c)-DATE(1996,01,01), 7) +
    MIN(1, 24/12*(MOD(Test_First_Contact_Date__c-DATETIMEVALUE('1996-01-01 12:00:00'), 1)))
))
-
(5*FLOOR((DATEVALUE(Test_DateCreated__c)-DATE(1996,01,01))/7) +
MIN(5,
    MOD(DATEVALUE(Test_DateCreated__c)-DATE(1996,01,01), 7) +
    MIN(1, 24/12*(MOD(Test_DateCreated__c-DATETIMEVALUE('1996-01-01 12:00:00'), 1)))
))
), 2)

I have a trigger that is only covered at 48% and I'm trying to get it closer to 100%. What can I do to up the code coverage?

Here's the trigger. The Bolded lines are not covered:

trigger trgAssetAfterInsertUpdateDelete on Asset (after insert, after update, after delete) {
    if (trigger.isInsert || trigger.isUpdate){
        /*Trigger will update the Client_Since__c field on the account with the first purchase date for all assets.
          If the Asset has VersaDoc and the account doesn't have a VersaDoc Project Account Team Member,
          it will assign the next VersaDoc Project manager from the assignment groups to the Account Team.*/
        // create a set of all the unique accountIds
        Set<id> accountIds= new Set<id>();
        Set<id> accountTeamAccountIds = new Set<id>(); // set of accountIDs that have VersaDoc in the asset
        for (Asset a : Trigger.new){
            accountIds.add(a.AccountId);
            if (a.HasVersadoc__c == 1 || a.HasVersadocStudio__c == 1 ) {
                accountTeamAccountIds.add(a.AccountId);
            }  
        }
          
        // create map of accountids and minimum purchase date
        map<ID, Date> acctSinceDate = new map<ID, Date>(); 
        AggregateResult[] groupedResults = [Select AccountId, MIN(PurchaseDate) MinPurchaseDate From Asset where AccountID in :accountIds GROUP BY AccountId];
        for (AggregateResult ar : groupedResults)  {
            acctSinceDate.put(String.valueof(ar.get('AccountId')), Date.valueof(ar.get('MinPurchaseDate')) );
        }      
        // create a map of accounts to update
        map<String, Account> accts = new map<String, Account>([Select Id, Client_Since__c from Account Where Id in :acctSinceDate.keySet()]);
        // update Account ClientSince field with MinimumPurchaseDate value
        //iterate over the list of accounts and assign the ClientSince date
        for (Account acct : accts.values()){
            acct.Client_Since__c = acctSinceDate.get(acct.Id);
        }
        if (accts.size()>0){
            update(accts.values());
        }
        // get the assignment group id for the VersaDoc Project Managers group         
        list<Assignment_Group_Name__c> asgnGroupNameIDs = [SELECT Id FROM Assignment_Group_Name__c WHERE Name = 'Support - VersaDoc Project Managers' limit 1];
        system.debug('asgnGroupnameIDs is ' + asgnGroupNameIDs);
   
        Assignment_Groups__c[] asgnGroups = new List<Assignment_Groups__c>([SELECT Group_Name__c, User__c, Last_Assignment__c, Millisecond__c
                                   FROM Assignment_Groups__c
                                   WHERE Group_Name__c in :asgnGroupNameIds
                                   AND Active__c = 'True' AND User_Active__c = 'True'
                                   ORDER BY Last_Assignment__c, Millisecond__c] );                                   
   
        Integer groupCount = asgnGroups.size();
   
        System.debug('>>>>>asgnGroups: '+asgnGroups);  
        if (asgnGroups.isEmpty()) return;                     

        //loop through list of accounts and get the accounts w/o VersaDoc Project Manager
        AccountTeamMember[] NewMembers = new AccountTeamMember[]{};  //list of new team members to add
        AccountShare[] newShare = new AccountShare[]{};  //list of new shares to add
        Map<id, Account> acctsToUpdate = new Map<id, Account>([Select a.Id, (Select Id, AccountId From AccountTeamMembers WHERE TeamMemberRole = 'VersaDoc Project Manager' limit 1) From Account a Where a.Id in :accountTeamAccountIds]);
        Integer cnt = 0;
        for (Account a : acctsToUpdate.values()){
            if (a.AccountTeamMembers == null || a.AccountTeamMembers.isEmpty()) {
                AccountTeamMember TeamMemberAd=new AccountTeamMember();
                TeamMemberAd.AccountId=a.id;
                TeamMemberAd.UserId=asgnGroups[cnt].User__c;
                TeamMemberAd.TeamMemberRole = 'VersaDoc Project Manager';
                NewMembers.add(TeamMemberAd);  
                datetime now = datetime.now();
                asgnGroups.get(cnt).Last_Assignment__c=now;
                asgnGroups.get(cnt).Millisecond__c = now.millisecondGMT();
                cnt ++;
                if (cnt == groupCount){ cnt = 0;}      
            }
        }


        //insert any valid members then add their share entry if they were successfully added
        Database.SaveResult[] lsr = Database.insert(NewMembers,false);
        Integer newcnt=0;
        for(Database.SaveResult sr:lsr){

            if(!sr.isSuccess()){
                Database.Error emsg = sr.getErrors()[0];
                system.debug('\n\nERROR ADDING TEAM MEMBER:'+emsg);
            }else{
                newShare.add(new AccountShare(UserOrGroupId=NewMembers[newcnt].UserId, AccountId=NewMembers[newcnt].Accountid, AccountAccessLevel='Edit',OpportunityAccessLevel='Edit'));
            }
                newcnt++;          
        }

        //insert the new shares
        Database.SaveResult[] lsr0 =Database.insert(newShare,false);
        Integer newcnt0=0;
        for(Database.SaveResult sr0:lsr0){
            if(!sr0.isSuccess()){
                Database.Error emsg0=sr0.getErrors()[0];
                system.debug('\n\nERROR ADDING SHARING:'+newShare[newcnt0]+'::'+emsg0);
            }
                newcnt0++;
        }
        // update assignment groups with their LastAssignmentDate
        update asgnGroups;                                          
    } else if (trigger.isDelete){

        // create a set of all the unique accountIds
        Set<id> accountIds = new Set<id>();
        for (Asset a : Trigger.old)
            accountIds.add(a.AccountId);   
          
        // create map of accountids and minimum purchase date
        map<ID, Date> acctSinceDate = new map<ID, Date>();
       
        AggregateResult[] groupedResults = [Select AccountId, MIN(PurchaseDate) MinPurchaseDate From Asset where AccountID in :accountIds GROUP BY AccountId];
        for (AggregateResult ar : groupedResults)  {
            acctSinceDate.put(String.valueof(ar.get('AccountId')), Date.valueof(ar.get('MinPurchaseDate')) );
        }
        // create a map of accounts to update
        map<string, Account> accts = new map <string, Account>([Select Id, Client_Since__c from Account Where Id in :accountIds]);
        for (Account acct : accts.values()){
            // if there's a value in the acctSinceDate map, update the Client_Since__c date to that date, otherwise set to null.
            if(acctSinceDate.ContainsKey(acct.Id)){
                acct.Client_Since__c = acctSinceDate.get(acct.Id);
            }else {
                acct.Client_Since__c = null;
            }
        }
        update(accts.values());
    }
}

Here's the Test class:
@isTest
private class TestTrgAssetAfterInsertUpdateDelete {
    static testMethod void myUnitTest() {
       //create runas user
        User u = TestDataFactory.createTestRunAsUser('Sales Assistant', 'Sales Assistant');
       
        System.runAs(u) {   
            Date firstPurchaseDate = date.newinstance(2013, 12, 15);
            Date newPurchaseDate = date.newinstance(2013, 11, 15); 
            list<Account> accts = new list<Account>();
            list<User> users = new list<User>();
           
            accts = TestDataFactory.createTestAccounts(2, 'Printers', 'Client');
            users = TestDataFactory.createMulitpleUsers(2, 'Standard User', 'Product Support Rep');
            Assignment_Group_Name__c agn = TestDataFactory.createAssignmentGroup('Support - VersaDoc Project Managers', 'Accounts');     
   
            Test.StartTest();  
                list<Asset> assts = new list<Asset>();
                //create assets for account and check that the client since date was populated
                TestDataFactory.CreateAssets(accts, firstPurchaseDate, 'PrinterPresence Silver Level', 'Purchased', 160.00, 2000.00);
                checkClientSinceDate(accts, firstPurchaseDate);
                performCreateAdditionalAssets(u.Id, accts);
                checkClientSinceDate(accts, firstPurchaseDate);
                performUpdateOriginalPurchaseDate(u.Id, accts, newPurchaseDate);
                checkClientSinceDate(accts, newPurchaseDate);
                performCreateVersaDocAssets(u.Id, accts);
                performDeleteAssets(u.Id, accts);  
                checkAccountTeamMember(accts, users);                                   
            Test.StopTest();     
        }
    }

    public static void checkClientSinceDate(list<Account> accounts, Date firstPurchaseDate){
          //check results of accounts to be sure ClientSince date was updated to the PurchaseDate
         list <Account> accs = [Select Id, Client_Since__c from Account Where Id in:accounts];
         for (Account a : accs){
            System.assertEquals(firstPurchaseDate, a.Client_Since__c);  
         } 
    }
   
    public static void performCreateAdditionalAssets(String userid, list<Account> accounts){
       //  list<Account> accts = new list<Account>([Select id from Account WHERE CreatedbyId =: userid and Id in : accounts]);            
        list <Asset> insertedAsst = [Select Id from Asset where CreatedbyId =: userid and AccountId in : accounts];     
        date now = date.today();
       
        //update previous asset to Attritioned-Upgrade
        for (Asset ass : insertedAsst){
            ass.Status = 'Attritioned-Upgrade';
            ass.UsageEndDate = date.today();
        }      
        update insertedAsst;
       
        // create new assets and check client since date
        TestDataFactory.CreateAssets(accounts, now, 'PrinterPresence Gold Level', 'Purchased', 210.00, 500.00);
    }
   
    public static void performUpdateOriginalPurchaseDate(String userid, list<Account> accounts, Date newPurchaseDate){    
        // get a list of the original assets   
        list <Asset> insertedAsst = [SELECT Id FROM Asset WHERE CreatedbyId =: userid AND AccountId in: accounts AND Status = 'Attritioned-Upgrade'];
               
        //update original asset purchase date
        for (Asset ass : insertedAsst){
            ass.PurchaseDate = newPurchaseDate;
        }      
        update insertedAsst;
    }
   
    public static void performDeleteAssets(String userid, list<Account> accounts){
        // delete assets for all accounts
        list <Asset> AssetToDelete = [Select Id from Asset where CreatedbyId =: userid and AccountId in: accounts];     
        delete AssetToDelete;
       
        checkClientSinceDate(accounts, Null);
    }
   
    public static void performCreateVersaDocAssets(String userid, list<Account> accounts){
        // add PrinterPresence Platinum level Asset (Has VersaDoc) and check that the VersaDoc Project Manager AccountTeam Members have been added to the account.
  list<Asset> assets = new list<Asset>();
        Set<id> accountIds= new Set<id>();
       
    TestDataFactory.createProduct('Platinum Level', 'VersaDoc');
   
        date now = date.today();
        assets = TestDataFactory.createAssets(accounts, now, 'Platinum Level', 'Purchased-Upgrade', 310.00, 7500.00);
        system.debug('-----assets are ' + assets);

        list <Asset> assetsVd = [select Id, Name, AccountId, HasVersadoc__c, HasVersadocStudio__c, Armor_date__c, Status, Product2Id, Product2.Name, Product2.ProductCode, Product2.Family, Product2.HasVersadoc__c FROM Asset where Id in: assets];
        system.debug('-------assetsVd are ' + assetsVd);
       
        Product2 prod = [select Id, Name, Included_Components__c, HasVersadoc__c from Product2 where Name =: 'Platinum Level'];
  system.debug('------products are ' + prod);

       // if asset contains versadoc product add to account list
        for(Asset a : assetsVd){
        if (a.HasVersadoc__c == 1 || a.HasVersadocStudio__c ==1){
          accountIds.add(a.AccountId);
         }          
     }
    }
   
    public static void checkAccountTeamMember(list<Account> accounts, list<User> users){
     // add users to assignment group
        AccountTeamMember[] NewMembers = new AccountTeamMember[]{};  //list of new team members to add
        AccountShare[] newShare = new AccountShare[]{};  //list of new shares to add
        Assignment_Group_Name__c agn = TestDataFactory.createAssignmentGroup('Support - VersaDoc Project Managers', 'Accounts');     
        TestDataFactory.addUsersToAssigmentGroup(users, agn);
            
        Assignment_Groups__c[] asgnGroups = new List<Assignment_Groups__c>([SELECT Group_Name__c, User__c, Last_Assignment__c, Millisecond__c
         FROM Assignment_Groups__c
            WHERE Group_Name__c =: agn.id
            AND Active__c = 'True' AND User_Active__c = 'True'
            ORDER BY Last_Assignment__c, Millisecond__c] );   
 
  Integer groupCount = asgnGroups.size();
  Map<id, Account> acctsToUpdate = new Map<id, Account>([Select a.Id, (Select Id, AccountId From AccountTeamMembers WHERE TeamMemberRole = 'VersaDoc Project Manager' limit 1) From Account a Where a.Id in :accounts]);
  Integer cnt = 0;
   for (Account a : acctsToUpdate.values()){
    system.debug('----acctsToUpdate.values is ' + acctstoUpdate.values());
   
       if (a.AccountTeamMembers == null || a.AccountTeamMembers.isEmpty()) {
        system.debug('---- in the If Statement ' + a.id);
           AccountTeamMember TeamMemberAd=new AccountTeamMember();
              TeamMemberAd.AccountId=a.id;
              TeamMemberAd.UserId=asgnGroups[cnt].User__c;
              TeamMemberAd.TeamMemberRole = 'VersaDoc Project Manager';
              NewMembers.add(TeamMemberAd);  
              datetime now = datetime.now();
              asgnGroups.get(cnt).Last_Assignment__c=now;
              asgnGroups.get(cnt).Millisecond__c = now.millisecondGMT();
              cnt ++;
              if (cnt == groupCount){ cnt = 0;}      
          }
    }   
       
        for (Account a : acctsToUpdate.values()){
            System.assertNotEquals(a.AccountTeamMembers, Null);
        } 
    }
}
I need help determining the logic to use in my flow. Basically, I want to call a flow from process builder that will create new records based on the value passed in from the process builder. We have a custom obejct (transaction) and a new records is created, if the frequency of the parent object of the transaction is "Annual", I need the flow to create 11 additional records with the date for each record equal to the first day of the next 11 months. If the frequency is "Quarterly", I need the flow to create 2 additional records with date equal to the first day of the next two months. If the Frequency is "Semiannual", I need the flow to create 5 additional records with the date of each one equal to the first day of the next 5 months. 

Is this somethig flow can do? My plan was to create a counter based on the frequency and then loop until the frequency counter is reached. However, I can't seem to figure out how to loop through anything other then a Salesforce object. However in this case the objects don't exist yet. 
I found this app on the appexchange that will validate if there is a primary contact on the opportunity. However, I also need to know if the primary contact has changed. This is a link to the app:
https://appexchange.salesforce.com/listingDetail?listingId=a0N300000025Vs1EAE

I'm trying to modify the code but am getting an error.
trigger updatecontactrolecount on Opportunity (before insert, before update){
Boolean isPrimary;
Integer iCount;
Boolean isPrimaryChanged;

Map<String, Opportunity> oppty_con = new Map<String, Opportunity>();//check if the contact role is needed and add it to the oppty_con map
for (Integer i = 0; i < Trigger.new.size(); i++) 
{
        oppty_con.put(Trigger.new[i].id,
        Trigger.new[i]);      
}
    
isPrimary = False; 
isPrimaryChanged = False;
for (list<OpportunityContactRole> oppcntctrle :[select OpportunityId, ContactID from OpportunityContactRole where (OpportunityContactRole.IsPrimary = True and OpportunityContactRole.OpportunityId in :oppty_con.keySet())]){
    if (oppcntctrle .Size() >0) {
         isPrimary = True; 
        //for (Opportunity o : trigger.new){
            //OpportunityContactRole contactRole =[select ContactID from OpportunityContactRole where IsPrimary = true and OpportunityId = :oppcntctrle.id];   
            for (list<OpportunityContactRole> oldContactRole :[select OpportunityID, ContactID from OpportunityContactRole where OpportunityContactRole.IsPrimary = True and OpportunityId IN :Trigger.oldMap.keySet()]){               
                if(oldContactRole.ID != oppcntctrle.ContactID){      
                    isPrimaryChanged = true;
                }           
               }    
        //}
    }     
}

iCount = 0;
for (List<OpportunityContactRole> oppcntctrle2 : [select OpportunityId from OpportunityContactRole where (OpportunityContactRole.OpportunityId in :oppty_con.keySet())])//Query for Contact Roles
{    
 if (oppcntctrle2 .Size()>0)
 {
 iCount= oppcntctrle2 .Size();     
 }
}
for (Opportunity Oppty : system.trigger.new) //Check if  roles exist in the map or contact role isn't required 
{
Oppty.Number_of_Contacts_Roles_Assigned__c = iCount;
Oppty.Primary_Contact_Assigned__c =isPrimary; 
Oppty.Primary_Contact_Changed__c= isPrimaryChanged;
}
}
I'm getting an error (Initial term of field expression must be a concrete SObject: List) on line 21  if(oldContactRole.ID != oppcntctrle.ContactID){  

What am I doing wrong?  
 
I've been told that I can parse the subject line of a case using flow and process builder but I really have no idea where to start. Can someone give me an outline of the steps I would take? I've done some investigating in flow but the only thing I can see that may work would be to use a loop variable but I don't know if I'm even heading in the right direction. 

Here's what I'm hoping to accomplish: 
We have cases that all come in from the same email address. The email address is not associated with any of the contacts on the accounts however they have the correct account number in the subject line of the case. I need to assign the case to the correct account based on the account number in the case subject line. All of the account numbers are six characters long. 

Here's an example of what the subject line would look like: "123456 Backups complete on "
I'm an admin trying to be a devleloper and am struggling. I'm trying to bulkify my trigger but am not sure how to assign multiple values from an aggregate query to a list. I've tried using a set, map and list but every example I see just has a Key and one value. I have two keys and multiple values.

My end goal is to update the case with the totalRevenue, TotalHours, and OverageHours from the billing. I have a related list of billing for each case. Each billing has a product that can have a different incident charge, per incident hours and possibly overage charge and each case can have multiple billings for the same product BUT only one case is counted as an incident. So if there are 4 billings with two different products, the incident charge would only be there once for each product, not four times for each billing. I wrote an aggregate query to get the sum of hours worked for each case and product. What I need to happen is for my trigger to loop through the aggregate results and for each case the for each product:

for case
loop through each product
if the totalHoursWorked > Per_Incident_hours__c then
total_hours =  (totalHoursWorked - incidentHours * overageCharge) + incidentCharge 
else total_hours = totalHoursWorked * incidentCharge
get next product
then update case TotalRevenue, TotalHours, TotalOverageHours
get next case

Here's what I have. However I don't know what to do with the AggregateResult set. 
trigger CaseClosed on Case (after insert, after update) {
    // this code will get the list of closed cases for Cloud IT records. It will loop through the billing for each case 
    // and calculate the total case revenue along with the Total Hours Worked and Case Overage Hours. 
    // list to hold updated case values
    List<Case> updateCase = new List<Case>();
    
   // get list of closed cases and add the case to the case list
   	set<id> caseIDs = new set<id>();
    for (Case c : trigger.new){
        	if (c.IsClosed && c.RecordTypeId == '012600000001COh') {
               	caseIDs.add(c.Id); 
                  system.debug('in CaseClosed trigger');
        	}
        } 
    
    // loop through the caseIDs and get billing for each product
    // create an aggregate Map of all billing for each case by product
    LIST<aggregateResult> results = ([SELECT Case__c, Product__c, MAX(Per_Incident_Hours__c) incidentHours, MAX(Incident_Charge__c) incidentCharge, MAX(Overage_Amount__c) overageCharge, SUM(Hours_Worked__c) totalHoursWorked FROM Billing__c  WHERE Case__c in : caseIds GROUP BY Case__c, Product__c]);  
    decimal total_hours = 0;
    decimal total_dollars = 0;
    decimal total_overage_hours = 0;
    
    // create a map to hold results from query
    Map<Id, ID> arCaseProduct = new Map<Id, Id>();
   list<Object> myList = new list<Object>();
    // loop through and get billing
    for (AggregateResult ar : results){
    	System.debug('in aggregate debug'+ar.get('Case__c')+'-'+ar.get('Product__c')+'-'+ar.get('incidentHours')+'-'+ar.get('incidentCharge')+'-'+ar.get('overageCharge')+'-'+ar.get('totalHoursWorked'));  
    	arCaseProduct.put((ID)ar.get('Case__c'), (id)ar.get('Product__c'));
        system.debug('arCaseProduct is '+ arCaseProduct);
    }
}



 
I've turned on duplicate alerts but need them to not run for Web to Lead forms. I've created a couple of duplicate rules but they don't seem to be working. The lead is not created and I get an email notifying me that the lead was not created because it's a duplicate. My user is the user that creates Web To Lead records and I'm the Sys Admin. I've created a couple of rules - one where the duplicate rule won't run if the

Current User: Profile is System Administrator
or
Current user: Username = is my emailaddress
or
Lead: Created By = my username.

I also followed instructions in this article for the other rule:
https://help.salesforce.com/HTViewSolution?id=000212677&language=en_US

Neither seem to be working. What am I doing wrong?
On our public Knowledge site, we created our own design with our own CSS which is responsive so we don't need the mobile site that comes with the app. However when you go to our site on a mobile device, it redirects to the pkb_mobile app. I've done the opposite of enabling it by following the instructions (page 12) of the install guide but it still redirects. https://appexchange.salesforce.com/servlet/servlet.FileDownload?file=00P3000000HCTKdEAP

On a mobile device, if you go to:
project-firespring.cs17.force.com/printerpresence
it will redirect to
project-firespring.cs17.force.com/printerpresence /pkb_mobile
How do I turn that off?
 
I'm not really a developer but have used apex in the past to write triggers. Now I'm trying to use the Rest API to make a call to GoToWebinar's API. I've written some code but am not sure how to test to see if my API call is even working. How do a test that from the Developer Console? Also, when I implement the feature, I am hoping to have it execute without human interaction as a job that runs each night. How do you do that?

Here's my code:
public class g2wCallout {
    public void getWebinars(){
      HttpRequest req = new HttpRequest(); 
      //Set HTTPRequest Method
      req.setMethod('GET');
    
      //Set HTTPRequest header properties
      req.setHeader('content-type', 'application/json');
      req.setHeader('Accept','application/json');
      req.setHeader('Authorization','OAuth ');
     
      req.setEndpoint( 'https://api.citrixonline.com/G2W/rest/organizers/3131084/historicalWebinars?fromTime=2015-05-28T18:00:00Z&toTime=2015-05-28T24:00:00Z' );
    
      //Set the HTTPRequest body	
       req.setBody('{"access_token":"blahblahblahblahblah"}'); 	
    
      Http http = new Http();
      
       try {
     
            //Execute web service call here		
           // HTTPResponse res = http.send(req);	
    
            //Helpful debug messages
             System.debug('this is a test');
            /*System.debug(res.toString());
          
            System.debug('STATUS:'+res.getStatus());
            System.debug('STATUS_CODE:'+res.getStatusCode());
            */
        } catch(System.CalloutException e) {
        //Exception handling goes here....
        }	
	}
}

 
I have 9 years of experience working with Salesforce.com:
  • Technical Solution Design, Documentation, and Training
  • Salesforce Development:  Apex, Visualforce
  • Salesforce Integration: , Web Services (SOAP, REST), JAVA, PHP, ASP.NET
  • System Administration
  • Business Analysis
I am a Salesforce Independent Software Vendor (ISV), and I’ve used Salesforce to manage my business for years. 

Contact me for an estimate for your project, and samples of how I can help increase your business productivity with Salesforce.com.
 
  • June 04, 2015
  • Like
  • 0