+ Start a Discussion
PRADEEP YADAV 3PRADEEP YADAV 3 

When an opportunity is inserted check for it’s duplicacy on the basis of its name and the account to which it is related to i.e. If it has same name and it’s linked to same Account then append “Duplicate Opportunity” in the name

trigger TriggerNew1Problem on Account(after insert)
{
    Set<String> setacc = new Set<String>();
    for(Account a : Trigger.new)
    {
        setacc.add(a.Name);
    }
    
    List<Account> acclist = [Select Id, Name, (Select Id, Name From Opportunities)
    From Account Where Name In : setacc
    ];
    List<Opportunity> opplist = new List<Opportunity>();
    
    Map<String, Account> nmap = new Map<String, Account>();
    for(Account a : acclist)
    {
        nmap.put(a.Name, a);
    }
    
    for(Account acc : Trigger.new)
    {
        if(nmap.get(acc.Name)!=null)
        {
            opplist.add(new Opportunity(AccountId =acc.Id, Name ='Duplicate Opportunity'+acc.Name, StageName = 'prospecting'
            , CloseDate = System.today()));         
        }
        else if(nmap.get(acc.Name)==null)
        {
             opplist.add(new Opportunity(AccountId =acc.Id, Name ='First Opportunity'+acc.Name, StageName = 'prospecting'
            , CloseDate = System.today()));
        }
    }
    if(opplist.size()>0)
    {
        insert opplist;
    }
}
when i inserted duplicate name in account then print duplicate opportunity name on the bases of account if not a duplicate account name then print first opportunity
But First Opportunity is not printed
Best Answer chosen by PRADEEP YADAV 3
Dave ShulmanDave Shulman
@Andrew

I gave it another go.  Does something like this one work properly?  
 
trigger TriggerNew1Problem on Opportunity (before insert) {
    Set<ID> setacc  = new Set<ID>();
    for (Opportunity oppty: Trigger.new){
        setacc.add(oppty.AccountID);
    }
    List<Account> AccList = [SELECT ID, Name, 
                            	(SELECT Name FROM Opportunities)
                            FROM Account WHERE
                            ID IN :setacc];
    Map<ID,List<String>> AccOppMap = new Map<ID,List<String>>();
    for (Account Acc: AccList) {
        List<String> OpptName = new List<String>();
        for (Opportunity o: Acc.Opportunities){
			OpptName.add(o.Name);
        }
        AccOppMap.put(Acc.Id, OpptName);
    }
    for (Opportunity tr : Trigger.new){
        if (AccOppMap.get(tr.AccountId).contains(tr.Name)) {
        	tr.Name = 'Duplicate Record ' + tr.Name;
        }
    }
}

 

All Answers

Agustin BAgustin B
Hi Pradeep you should do a before insert, not an after insert, its more efficient for this use case.
That way you dont have to insert opplist, the trigger will do that for you, you just check that that account does not have another opportunity and if it has then change the fields you want.

If it helps you please mark this as correct, it may help others.
MoonpieMoonpie
Hi Pradeep,

Why did you create this new question post, when you never responded to my last post in this same question here (https://developer.salesforce.com/forums/ForumsMain?id=9062I000000XxtEQAS)?

It appears that you did change your Map from <Id, Account> to <String, Account> as I alluded to.

But as stated, you did not respond to my comment/question about whether you were really supposed to be comparing Account names or Opportunity names; as well as my question about what exactly the issues or errors were.

Seriously, why repost when you are the one who abandoned the other post thread, not me?
Dave ShulmanDave Shulman
Hey my friend!  The way im understanding this it should be a trigger on the Opportunity instead of the account.  It should fire when a new opportunity is created then check to see if there are any other opportunites with the same name & related account.   I have given a shot at trying to create this trigger.  Take a peek and see if something like this is more what you wanted.  
 
trigger TriggerNew1Problem on Opportunity (before insert) {
	Integer Counter = 0;
    Set<String> OpptyNames = new Set<String>();
    Set<ID> setacc  = new Set<ID>();
    List<Opportunity> opplist  = new List<Opportunity>();
    for (Opportunity oppty: Trigger.new){
        OpptyNames.add(oppty.Name);
        setacc.add(oppty.AccountID); 
    }
    List<Account> AccList = [SELECT ID, Name, 
                            	(SELECT Name FROM Opportunities
                            	 WHERE Name IN :OpptyNames
                                 ORDER BY CreatedDate ASC)
                            FROM Account WHERE
                            ID IN :setacc];
    for (Account Acc: AccList) {
        for (Opportunity o: Acc.Opportunities){
            if (counter > 0) {
                O.Name = 'Duplicate Opportunity ' + O.Name;
                opplist.add(o);
            }
            counter++;
        }
        counter = 0;
    }
    if (opplist.size() > 0) {
        Upsert opplist;
    }
}

 
PRADEEP YADAV 3PRADEEP YADAV 3
Hi,Dave
one question to you upsert operation will be using in trigger . code will be work but not inserting duplicate record
Dave ShulmanDave Shulman
you can flip that to an insert instead, and also check that your org has no duplicate rules preventing you from creating the duplicate at all.  You might not be able to insert the records because a rule is blocking all duplicates
SidPSidP
Dave Shulman 

Your code will update Duplicate Opportunity to the existing one and not the newly created one.

Pradeep, You may give a try to the below code and let me know if that works for you.
 
Mark best answer if this resolves your issue.

-Sid
trigger DupOpptyCheck on Opportunity (before insert) {
	Map<String, Id> oppNameAccIdMap = Set<String, Id>();
    for (Opportunity oppty : trigger.new) {
    	oppNameAccIdMap.put(oppty.Name, oppty.AccountId);
    }


    Map<String, String> oppExist = new Map<String, String>();
    for (Opportunity opp : [SELECT Name, Id, AccountId, Account.Name
    									FROM Opportunity
    									WHERE Name =: oppNameAccIdMap.keySet()] ) {
    	if (oppNameAccIdMap.get(opp.Name) == opp.AccountId) {
    		// If the OpptyName and the AccountId is the same then it's duplicate
    		oppExist.put(opp.Name, opp.Account.Name);
    	}
    }

    for (Opportunity newOppty : Trigger.new) {
    	if (oppExist.containsKey(newOppty.Name)) { // If dup oppty
    		newOppty.Name = 'Duplicate Oppty ' + oppExist.get(newOppty.Name); // Apend account name
    	}
    }

}
Andrew GAndrew G
@moonpie - yep, i hate that too

@Dave
not a bad effort, however, what happens on a bulk insert of multiple opportunities against a single Account?  Also, i believe what your code would do would update the existing (previously inserted) Opportunity name, not the name on the Oppty being inserted.

@pradeep

Dave is correct to say that the trigger should be on the Opportunity.  And as a before insert, as we are manipulating the values before inserting and therefore trying to reduce the number of DMLs in the event.

If it was me, I would step back to psuedo code to resolve the logic and bulkificaton issues:
 
On before insert of one or more oppty

Loop the trigger records to build a Set of Ids for Accounts

Do a query on Account & related Opportunities

Build a Map < AccountId, List<String> OpportunityName>

Then loop the trigger records

  do a get on the map using the Account Id in the Opportunity
  
  do a list.contains() on the list of Strings that are existing names using the new oppty name

  action the new name accordingly

end loop

regards
Andrew
 
Dave ShulmanDave Shulman
@Andrew 
Im a pretty new developer so i appreciate it!

Correct me if im wrong but wont my code update the name of the second duplicate child opportunity, the one that has the most recent create date (which would be the one thats being inserted)

or in the case of inserting many @the same account, it would mark duplicate to all but 1.

Do querys in before triggers not include inserts in trigger.new yet? 
PRADEEP YADAV 3PRADEEP YADAV 3
Thanks Dave Shulman
Andrew GAndrew G

@Dave

if you check your logic, you have the query results, being the existing records.  Remember, you are in a "before insert" trigger so you are querying what already exists, not the current record being inserted.  

if we did a bulk insert, and inserted 2 x oppty with name Alpha and Bravo, and there were existing Alpha and Bravo named oppty, then the oldest of the original pair would be unchanged, but the second would be "Duplicate Opportunity Bravo".  The insert/upsert would occur. And then the DML event for the trigger would happen.  That is the two records that kicked off the trigger would be inserted. 

You would then end up with 4 x Oppty, with Names "Alpha","Duplicate Opportunity Bravo", "Alpha","Bravo"

@SidP
Nice code example.  Similar concept to my suggested psuedo code by building a map and looping the map against the trigger elements
Only point, 
oppNameAccIdMap.keySet() would return a list, even if only one item in the list, so the query should be written using the IN keyword:
 

for (Opportunity opp : [SELECT Name, Id, AccountId, Account.Name
    									FROM Opportunity
    									WHERE Name IN 
:oppNameAccIdMap.keySet()] ) {


Regards
Andrew
PRADEEP YADAV 3PRADEEP YADAV 3
Thanks Andrew
Dave ShulmanDave Shulman
@Andrew

I gave it another go.  Does something like this one work properly?  
 
trigger TriggerNew1Problem on Opportunity (before insert) {
    Set<ID> setacc  = new Set<ID>();
    for (Opportunity oppty: Trigger.new){
        setacc.add(oppty.AccountID);
    }
    List<Account> AccList = [SELECT ID, Name, 
                            	(SELECT Name FROM Opportunities)
                            FROM Account WHERE
                            ID IN :setacc];
    Map<ID,List<String>> AccOppMap = new Map<ID,List<String>>();
    for (Account Acc: AccList) {
        List<String> OpptName = new List<String>();
        for (Opportunity o: Acc.Opportunities){
			OpptName.add(o.Name);
        }
        AccOppMap.put(Acc.Id, OpptName);
    }
    for (Opportunity tr : Trigger.new){
        if (AccOppMap.get(tr.AccountId).contains(tr.Name)) {
        	tr.Name = 'Duplicate Record ' + tr.Name;
        }
    }
}

 
This was selected as the best answer
PRADEEP YADAV 3PRADEEP YADAV 3
Hi Shulman
What way doing lead conversion in trigger
Sushant Mandewar 46Sushant Mandewar 46
Hi Dave,

your answer looks correct but i dont see any point in creating a map there the solution can be taken care in a very simple way following all the BEST PRACTICES as below and it works.

trigger OpportunityDupe on Opportunity (before insert,before update) {
    set<String> oppName = new Set<String>();
    set<Id> accId = new set<Id>();
    for(Opportunity opp: Trigger.new){
        oppName.add(opp.Name);
        accId.add(opp.AccountId);
    }
    
    List<Opportunity> oldOppList = [select Id,AccountId,name from Opportunity where name IN:oppName AND AccountId IN:accId];
    
    for(Opportunity opps: Trigger.new){
        if(oldOppList.size() > 0){
            opps.Name=opps.Name+' '+'Duplicate Opportunity';
        }
    }
}