Trigger to prevent User From Adding more than one product to an opportunity - triggers

So i have written a trigger to prevent user from entering more than one opportunity product to the same opportunity, but the problem is when he adds more than one opportunity product at the same time, my trigger does not fire, salesforce takes it as one product.
What can i add to my trigger to fix this ?
My trigger :
trigger OpportunityLineItemBeforeInsert on OpportunityLineItem (before insert) {
Set<Id>opportunityIds = new Set<Id>();
// get all parent IDs
for(OpportunityLineItem i : trigger.new)
{
opportunityIds.add(i.OpportunityId);
}
// query for related Olis (Opportunity Line Items)
Map<Id, Opportunity> opps = new Map<Id, Opportunity>([SELECT ID,
(SELECT ID
FROM OpportunityLineItems)
FROM Opportunity
WHERE ID IN :opportunityIds]);
for(OpportunityLineItem i : trigger.new)
{
if(opps.get(i.OpportunityId).OpportunityLineItems.size()>0)
{
i.addError('Your Message');
}
}
}
Thank you in advance.

I would probably ignore anything related to the Oppty.
You want only one product created, so on creation, either the number of LI is 0 and you can create exactly one, or it' snot 0 and you can't create any.
I would just create a rollup field on the Oppty, count the products. If the count != 0, then fail the validation. If count = 0, then count the Olis in trigger.new and if !=1, fail.

Instead of writing code to do this you should instead create a field on products that stores the id of the parent opportunity, make that field unique, and populate the value via workflow or process builder with the id of the parent opportunity. That way if a second product gets added the unique constraint would fire and prevent the record from being inserted.
Another option would be to create a rollup on opportunity to count the number of opportunity products, then add a validation rule that show an error if the number of products > 1. The advantage of doing it this way is that you get to set the error message as opposed to the generic duplicate error message with the first option.

Related

How to merge two leads using an apex Trigger

I'm new to salesforce and I'm trying to learn more. Currently I'm stuck at a point where I don't know what to do further. Kindly point me in the right direction. Any help is appreciated.
So what im trying to do is to compare lastnames to find duplicates when the record is being created and if a duplicate is found then instead of creating it as a new record it should be merged with existing record.
So to achieve the task I have wrote the following trigger handler:
public class LeadTriggerHandler {
public static void duplicateMerge(){
List<Lead> leadList = [SELECT Id,Name, Email, Phone, FirstName, LastName FROM Lead];
List<Lead> leadTrigger = Trigger.new;
for(Lead leadVarTrigger : leadTrigger){
for(Lead leadVar : leadList){
//System.debug(leadVar.LastName + '==' + leadVarTrigger.LastName);
if(leadVarTrigger.LastName == leadVar.LastName)
{
//System.debug(leadVar.LastName + '==' + leadVarTrigger.LastName);
//leadVarTrigger.addError('This is a duplicate record');
Database.merge(leadVar, leadVarTrigger);
System.debug('Trigger Successful');
}
}
}
}
}
the following is my trigger:
trigger LeadTrigger on Lead (after insert) {
if(Trigger.isafter && Trigger.isInsert)
{
LeadTriggerHandler.duplicateMerge();
}
}
And when I try with after insert i get the following error:
LeadTrigger: execution of AfterInsert caused by: System.DmlException: Merge failed. First exception on row 0 with id 00Q5j00000ENUGVEA5; first error: INVALID_FIELD_FOR_INSERT_UPDATE, Unable to create/update fields: Name. Please check the security settings of this field and verify that it is read/write for your profile or permission set.: [Name] Class.LeadTriggerHandler.duplicateMerge: line 18, column 1 Trigger.LeadTrigger: line 5, column 1
And if i try with before trigger i get the following error for the same code:
LeadTrigger: execution of BeforeInsert caused by: System.StringException: Invalid id at index 0: null External entry point Trigger.LeadTrigger: line 5, column 1
Actually, according to your code, you are allowing the record to be created and saved to the database by using after insert. Your before insert failed because your handler class is referencing an Id, however, if you use before logic, the record isn't saved to the database yet, meaning it doesn't have an Id. With that being said, let's try the following. :)
The Trigger (Best practice is to have one trigger with all events):
trigger TestTrigger on Lead (before insert, before update, before delete, after insert, after update, after delete, after undelete) {
if(Trigger.isafter && Trigger.isInsert)
{
//Can't conduct DML operations with trigger.new or trigger.old
//So we will create a set and send this to our handler class
Set<Id> leadIds = Trigger.newMap.keySet();
LeadTriggerHandler.duplicateMerge(leadIds);
}
}
The Handler Class:
public class LeadTriggerHandler {
public static void duplicateMerge(Set<Id> idsFromTrigger){
//Querying the database for the records created during the trigger
List<Lead> leadTrigger = [SELECT Id, LastName FROM Lead WHERE Id IN: idsFromTrigger];
List<String> lastNames = new List<String>();
//This set is important as it prevents duplicates in our dml call later on
Set<Lead> deDupedLeads = new Set<Lead>();
List<Lead> leadsToDelete = new List<Lead>();
for (Lead l : leadTrigger){
//getting all of the Last Names of the records from the trigger
lastNames.add(l.lastName);
}
//We are querying the database for records that have the same last name as
//the records that were created during our trigger
List<Lead> leadList = [SELECT Id, Name, Email, Phone, FirstName, LastName FROM Lead WHERE LastName IN: lastNames];
for(Lead leadInTrigger : leadTrigger){
for(Lead leadInList : leadList){
if(leadInTrigger.LastName == leadInList.LastName){
//if the lead from the trigger has the same last name as a lead that
//already exists, add it to our set
deDupedLeads.add(leadInTrigger);
}
}
}
//add all duplicate leads from our set to our list and delete them
leadsToDelete.addAll(deDupedLeads);
delete leadsToDelete;
}
}
This handler has been bulkified in two ways, we removed the DML operation out of the loop and the code is able to process a scenario where someone mass inserts 1000s of leads at a time. Plus, rather than querying every lead record in your database, we only query for records that have the same last name as the records created during the insert operation. We advise using something more unique than LastName like Email or Phone as many people/leads can have the same Last Name. Hope this helps and have a blessed one.

APEX Trigger when a textfield gets updated

I am trying to create a trigger in APEX, when an custom textfield of an custom sObject gets updated with products (means, when new products get insert or existing one get deleted).
How can I compare in APEX the Trigger.Old values with the Trigger? New values of this field in order to start the Trigger.
It would look something like this:
Trigger NameOfTrigger on CustomSObject__c (after update){
/*there is already an existing list of products that get insert into the custom textfield (probably as Strings)
*/
List <String> textList = new List <String> ();
/*PseudoCode: if the textfield got updated/has changed, copy from every entry of this textfield (entry = product name as a string) and copy fieldX into another sObject
*/
if(CustomSObject.field(OldValues) != CustomSObject.field(NewValues)){
for (String product : textList){
//Trigger e.g. copy the values of a certain field of p and paste them in another sObject
}
Could somebody help me with the syntax?
You can utilize inbuilt Trigger.new and Trigger.old to get the latest and old values of any record. These lists can be used to achieve what you're looking for.
Sample example would be:
Trigger NameOfTrigger on CustomSObject__c (after update){
for(CustomSObject__c customObject : Trigger.new) {
// get old record
CustomSObject__c oldCustomObject = Trigger.oldMap.get(customObject.Id);
// compare old and new values of a particular field
if(customObject.fieldName != oldCustomObject.fieldName){
//Trigger e.g. copy the values of a certain field of p and paste them in another sObject
}
}
}
See documentation of Trigger.new & Trigger.old

Apex code to update new Opportunity with values from related object

What would be the proper method to update a list of new Opportunities with the values from a related record.
for (Opportunity opps:Trigger.new){
[SELECT Id, CorpOwner__r, Contact__r,(SELECT Id, AccountLocation from Account)]
o.CorpOwner__r =Account.Id; o.AccountLocation = opps.Account.AccountLocation;
insert opps
Do you call the lookup fields by the __r suffix? Could you do a before insert operation and still look up the Opportunity.CorpOwner__r relationship to values in the CorpOwner__r Account record, or does that relationship not exist since the record has not been created? What would be a proper batchified way to go about it?
Here's a possibility that demonstrates a number of concepts:
trigger UpdateOpptyWithAccountInfo on Opportunity (before insert) {
// Keep this SOQL query out of the FOR loop for better efficiency/batching
Map<Id, Account> relatedAccounts = new Map<Id, Account>(
[SELECT Id, AccountLocation__c
FROM Account
WHERE Id IN
(SELECT AccountId
FROM Opportunity
WHERE Id = :Trigger.new)
]
);
for (Opportunity o : Trigger.new) {
/* Find each opportunity's Account in the map we queried for earlier
* Note: there's probably a more efficient way to use a Map of Opportunity IDs to Account objects...
* This works fine and could be more readable.
*/
for (Account a : relatedAccounts.values()) {
if (a.Id == o.AccountId) {
// Once you've found the account related to this opportunity, update the values
o.CorpOwner__c = a.Id;
o.AccountLocation__c = a.AccountLocation__c;
}
}
}
// We're still inside an `insert` trigger, so no need to call `insert` again.
// The new fields will be inserted along with everything else.
}
If you're establishing the relationship between objects, use the __c suffix:
o.CorpOwner__c = a.Id; // Associate Account `a` as Opportunity `o`'s CorpOwner
If you're looking up a field on a related object, then you would use __r:
System.debug(o.CorpOwner__r.Name); // Print Opportunity `o`'s CorpOwner's name

Trigger to update a custom lookup field on opportunity

I created a custom object XtendedUser which has an id and Name.
I created a custom lookupfield on Opportunity called "XtendedUser__c" which links the opportunity to the corresponding XtendedUser record.
Now I made it so that the name of an opportunityowner corresponds to the name of an XtendedUser-record, so I want the trigger to autopopulate the custom lookup field "XtendedUser__c" on the opportunity with the id of the corresponding XtendedUser-record of which the name matches the name of the opportunityowner.
I never wrote a trigger, always worked with workflows and fieldupdates, but I've got to make this work. So if you could please help me with this? I would be extremely greatfull!
Thanks in advance
You should use a map to link the records and retrieve the value before the insert of a new record and before the update of an existing record. This technique will also allow you to bulk update all your records. It should be something like:
trigger ExtendedUser__c on Opportunity (before insert, before Update) {
list<id> oid = new list<id>();
for(opportunity o: trigger.new){
oid.add(o.id);
}
map<id, ExtendedUser__c> ExtendU = new map<id, ExtendedUser__c>(
[select name from ExtendedUser__c where id in: oid]);
for(opportunity o: trigger.new){
o.name = ExtendU.get(o.id).name;
}
}

Creating a Trigger that will create a new Opportunity Owner every time a there is a new Opportunity in Salesforce

I'm new to Salesforce and I'm trying to create a trigger that will basically update fields and create a new Opportunity owner every time a new Opportunity gets added.
For clarity, I've attached my code below:
trigger trig_Opportunity_CreateOppOwner on Opportunity (before insert, before update) {
//Opportunity OppOwner = null;
List<id>OppsID = new List<id>(); //Get the id of all new Opportunities owners
for (Opportunity Opp : Trigger.new) { //If a new Opportunity is added, then create new OppOwner, if not, then don't add.
OppsId.add(Opp.ID); //adds all new Opportunities Id's
}
List<Opportunity>OppToUpdate = [SELECT Id,
Name,
Owner__c,
OppOwner,
FROM Opportunity
WHERE Id IN: Opp.ID // Select Id, OpportunityName,
];
if Trigger.oldMap.get(opp.id).Owner__c != Trigger.oldMap.get(OppToUpdate.id).Owner__c // verify that if previous Opportunity has a matching owner.
OppsId.add(Opp.ID); //populates new oppowner with ID's of all owners.
This is basically what I'm trying to do:
Trigger(Before Update, Before Insert){
Get all Triggered Opportunities.
Verify if old opportunities already has a matching Owner.
If it's not a matching owner, update Opportunity fields and update the opportunity.
I'm not sure how to get from step 2 to step 3. Any help would be appreciated.
By the code that you provided isn't clear where it's finished, from my side seems that after couples of lines that you've provided another couples of lines exists. Could you please post all your code? If it isn't so, and code that you posted is all your code, from my point of view, this code do nothing, absolutely nothing.
Why?
no validation's errors
no DML operation
trigger trig_Opportunity_CreateOppOwner on Opportunity (before insert, before update) {
//Opportunity OppOwner = null;
/*
List<id>OppsID = new List<id>(); //Get the id of all new Opportunities owners
for (Opportunity Opp : Trigger.new) { //If a new Opportunity is added, then create new OppOwner, if not, then don't add.
OppsId.add(Opp.ID); //adds all new Opportunities Id's
}
*/
// 3 started lines might be replaced by the following one
List<id>OppsID = Trigger.newMap.getKeys();
//but the following code perform select on Opportunity object and return the same list as Trigger.new
// OppToUpdate == Trigger.new
// What for? May be you should work with this part on "after insert/update"
List<Opportunity>OppToUpdate = [SELECT Id,
Name,
Owner__c,
OppOwner,
FROM Opportunity
//WHERE Id IN: Opp.ID // Opp - isn't exist and it isn't list/set of id
WHERE Id IN OppsId // I guess you meant this
];
// 1.variable "opp" isn't exist here
// 2. "OppToUpdate.id" - you can't use list in this manner
if Trigger.oldMap.get(opp.id).Owner__c != Trigger.oldMap.get(OppToUpdate.id).Owner__c // verify that if previous Opportunity has a matching owner.
OppsId.add(Opp.ID); //populates new oppowner with ID's of all owners.