Salesforce Trigger Test Class - triggers

below is my Apex Trigger. I am a beginner and trying to write its test class but continuously getting error "System.DmlException: Insert failed. First exception on row 0; first error: REQUIRED_FIELD_MISSING, Error: You can't select products until you've chosen a price book for this opportunity on the products related list.: []".
trigger TrgrOptyHighestCustmorePrice on Opportunity (before insert, before update)
{
public Id oid;
public String bidType;
public String BUCode;
for(Opportunity o : trigger.new)
{
oid = o.Id;
bidType = o.BidType__c;
BUCode = o.Business_Line_BU__c;
}
List<OpportunityLineItem> oliList = new list<OpportunityLineItem>([SELECT id, Customer_Price__c, ReCat_Product_Line__c
FROM OpportunityLineItem
WHERE OpportunityId =: oid ORDER BY
Customer_Price__c DESC LIMIT 1]);
for(OpportunityLineItem oli : oliList)
{
if(bidType == 'Competitive' && oli.ReCat_Product_Line__c == 'DMS')
{
BUCode = 'BL.619';
}
if(bidType == 'Competitive' && (oli.ReCat_Product_Line__c == 'EMS' || oli.ReCat_Product_Line__c == 'GMS'))
{
BUCode = 'BL.620';
}
if(bidType == 'Competitive' && oli.ReCat_Product_Line__c == 'MMS')
{
BUCode = 'BL.622';
}
if(bidType == 'Sole Sourced' && oli.ReCat_Product_Line__c == 'DMS')
{
BUCode = 'BL.624';
}
if(bidType == 'Sole Sourced' && (oli.ReCat_Product_Line__c == 'EMS' || oli.ReCat_Product_Line__c == 'GMS'))
{
BUCode = 'BL.621';
}
if(bidType == 'Sole Sourced' && oli.ReCat_Product_Line__c == 'MMS')
{
BUCode = 'BL.623';
}
}
for(Opportunity opt : trigger.new)
{
opt.Business_Line_BU__c = BUCode;
}
}
Test Class
#isTest(seeAllData=true)
public class Test_TrgrOptyHighestCustmorePrice {
private static testmethod void TrgrOptyHighestCustmorePriceTest(){
Test.startTest();
//Insert a test product.
Product2 p1 = new Product2(Name='Product Monthly 1111', isActive=true, CurrencyIsoCode='USD', ReCat_Product_Line__c = 'DMS');
insert p1;
// Get standard price book ID.
Id pricebookId = Test.getStandardPricebookId();
// Insert a price book entry for the standard price book.
PricebookEntry standardPrice = new PricebookEntry(
Pricebook2Id = pricebookId, Product2Id = p1.Id,
UnitPrice = 10000, IsActive = true);
insert standardPrice;
Pricebook2 customPB = new Pricebook2(Name='Custom Pricebook', isActive=true);
insert customPB;
PricebookEntry customPrice = new PricebookEntry(
Pricebook2Id = customPB.Id, Product2Id = p1.Id,
UnitPrice = 12000, IsActive = true);
insert customPrice;
// Insert Opportunity
Opportunity opt = new Opportunity(Name='Test',StageName='Prospect',
CloseDate=date.today(),BidType__c = 'Competitive',
Business_Line_BU__c = 'BL.619',
PriceBook2 = customPB);
insert opt;
OpportunityLineItem optLI = new OpportunityLineItem(OpportunityId = opt.id, Product2Id = p1.Id);
insert optLI;
update opt;
Test.stopTest();
}
}
I am unable to understand how can I test my simple trigger.

Its because u do not fill all required fields for the Opportunity Line Item. See: https://developer.salesforce.com/docs/atlas.en-us.api.meta/api/sforce_api_objects_opportunitylineitem.htm for required fields.
This as an example will work:
OpportunityLineItem optLI = new OpportunityLineItem(OpportunityId = opt.id, Product2Id = p1.Id, TotalPrice = 100, PricebookEntryId=customPrice.Id, Quantity =3);

First Insert the opportunity.
Then update the opportunity with the pricebookid.
// Insert Opportunity
Opportunity opt = new Opportunity(Name='Test',StageName='Prospect',
CloseDate=date.today(),BidType__c = 'Competitive',
Business_Line_BU__c = 'BL.619'
);
insert opt;
opt.PriceBook2 = customPB;
update opt;

Related

Once Case is created with updated fields, The updated fields should be updated in Account

trigger Ecare_Trg_UpdateContCoreData on Case (after update) {
List<AccountContactRelation> arcList = New List<AccountContactRelation>();
for(Case c: Trigger.New)
{
if(c.Status =='Closed' && c.Type == 'Commercial' && c.vlocity_cmt__Reason__c =='Change Request' && c.Description == 'Haupaddressdurang')
{
AccountContactRelation ct = [SELECT ContactId,AccountId From AccountContactRelation Where AccountId =: c.AccountId];
ct.Contact.FirstName = c.First_Name__c;
ct.Contact.LastName = c.Last_Name__c;
ct.Contact.Salutation = c.Salutation__c;
ct.Account.BillingCity = c.City__c;
ct.Account.BillingPostalCode = String.ValueOf(c.Postal_Code__c);
ct.Account.BillingStreet = c.Street__c;
arcList.add(ct);
System.debug(c.AccountId);
}
}
if(arcList.size()>0){
upsert arcList;
}
}
I need to update the update case details in Account By this trigger i am not able update how we can do it?

i am having problem where recursion is happing in apex triggers it start where i have written PROBLEM HERE

this part works fine
1.no problem here in this part of code.
trigger intertask_3 on Campaign (before insert, before update,after update) {
List<CampaignMember> updList = new List<CampaignMember>();
if(trigger.isbefore && trigger.isinsert){
for(Campaign camp : trigger.new){
if(camp.Capping__c == true){
if(camp.Capping_Value__c == null || camp.Capping_Value__c <= 1){
camp.Capping_Value__c.addError(' value cant be empty, 0 and negative');
}
}
}
}
//for error
if(trigger.isbefore && trigger.isupdate){
set<id> campId = new set<id>();
for(Campaign camp : trigger.new){
if(camp.Name != null){
campId.add(camp.Id);
}
}
list<CampaignMember> cm = [select id from CampaignMember where status = 'Registered' and CampaignId in : campId];
integer count = integer.valueOf(cm.size());
//system.debug(count);
for(Campaign campM : trigger.new ){
//system.debug(campM.Capping_Value__c );
if(campM.Capping__c == true){
if(campM.Capping_Value__c < count){
//system.debug(count);
campM.Capping_Value__c.addError('value cant be less than registered member');
}else if (campM.Capping_Value__c == count){
campM.Capping_Value__c.addError('cant update same value');
}
}
}
}
if(trigger.isafter && trigger.isupdate){
set<id> campId = new set<id>();
for(Campaign camp : trigger.new){
Campaign campo = trigger.oldMap.get(camp.Id);
if(camp.Capping__c == true){
if(camp.Capping_Value__c != campo.Capping_Value__c ){
campId.add(camp.Id);
}
}
}
Map<id,integer> cmapIdandCMno = new Map<id,integer>();
List<Campaign> campContainReg = [select id,(select id from CampaignMembers where status = 'Registered') from Campaign where id in : campId];
for(Campaign camp : campContainReg){
cmapIdandCMno.put((id)camp.Id,(integer)camp.CampaignMembers.size());
}
// number of registered campaignmember
//list<CampaignMember> cm = [select id from CampaignMember where status = 'Registered' and CampaignId in : campId];
//integer count = integer.valueOf(cm.size());
//all CampaignMember
//for(CampaignMember campM :[select id,status,Campaign.Id,Campaign.Capping_Value__c from CampaignMember where CampaignId in : cmapIdandCMno.keySet() ] ){
//integer size = integer.valueOf(cmapIdandCMno.get(campM.Campaign.Id));
// system.debug(size);
// }
/*
list<CampaignMember> camMno = [select id,Campaign.Id from CampaignMember where CampaignId in :cmapIdandCMno.keySet() ];
integer size = integer.valueOf(camMno.Campaign.Id);
system.debug(size);
}*/
**PROBLEM FORM HERE **
problem with size varibale , i could not understand where to put it so that it does not loop 5 times at the same time.
it looks like my else statement is not working at all.
//in this for loop all members are getting registered instead of following the if else
statement
for(CampaignMember campM :[select id, status, Campaign.Id, Campaign.Capping_Value__c from CampaignMember where CampaignId in : cmapIdandCMno.keySet() ] ){
//for(id mapid : cmapIdandCMno.keySet()){
integer size = integer.valueOf(cmapIdandCMno.get(campM.Campaign.Id));
//system.debug(size);
//}
if(size < campM.Campaign.Capping_Value__c && (campM.Status == 'Waitlisted' || campM.Status == 'Engaged')){
campM.Status= 'Registered';
updList.add(campM);
size++;
system.debug(size);
}
else if( size == campM.Campaign.Capping_Value__c){
campM.Status= 'Waitlisted';
updList.add(campM);
}
}
//system.debug(size);
}
update updList ;
}

Apex Code to get input value from opp using before insert trigger

Hi Everyone help me to get output.
WHERE shipDate__c >= :startDate AND return_date__c <= :endDate
In the above code startDate & endDate retrives the data (already Inserted Record) from db.
for eg:
startDate = 20-03-2021
endDate = 16-04-2021
WHERE shipDate__c >= :20-03-2021 AND return_date__c <= :16-04-2021
but what i need is, While editing the record by changing startDate, it retrives the entered data before saving in db.
for eg:
startDate = 26-03-2021
WHERE shipDate__c >= :26-03-2021 AND return_date__c <= :16-04-2021
Hope someone will help
Thank you
public void onBeforeUpdate(List<Opportunity> newMap){
Set<String> oppIds = new Set<String>();
for(Opportunity opp: newMap){
oppIds.add(opp.id);
}
if(oppIds.size() > 0 && oppIds != null){
//get all record of product with Opp Id
List<OpportunityLineItem> productList = [SELECT Product2.m_ProductGroup__r.Name, OpportunityId, Opportunity.shipDate__c,
Opportunity.return_date__c FROM OpportunityLineItem
WHERE OpportunityId IN :oppIds
AND IsDeleted = false
];
if(productList.size() > 0 && productList !=null){
for(OpportunityLineItem product: productList){
totalUsed = 0;
String name = product.Product2.m_ProductGroup__r.Name;
Date startDate = product.Opportunity.shipDate__c;
Date endDate = product.Opportunity.return_date__c;
if(name != ''){
totalUsed = getSum(name, startDate, endDate);
if( totalUsed <= 30 ){
for(Opportunity opp: newMap) {
opp.m_enableproduct__c = true;
}
}
}
}
}
}
}
private Decimal getSum(String productName, Date startDate, Date endDate){
Decimal sum = 0;
List<Opportunity> dataList = new List<Opportunity>();
List<OpportunityLineItem> productList = new List<OpportunityLineItem>();
dataList = [SELECT id, shipDate__c, return_date__c FROM Opportunity WHERE shipDate__c >= :startDate AND return_date__c <= :endDate];
if(dataList != null && dataList.size() > 0){
for(Opportunity opp :dataList){
productList = [SELECT Quantity FROM OpportunityLineItem
WHERE OpportunityId =:opp.id
AND Product2.m_ProductGroup__r.Name =: productName
AND IsDeleted = false
];
if(productList != null && productList.size() > 0 ){
for(OpportunityLineItem addTemp :productList){
sum += addTemp.Quantity;
}
}
}
system.debug('sum' + sum);
}
return sum;
}

Create a cycle in T-SQL from the list

I have code written in C#, but I want to create a T-SQL script to run on the server. This is part of my C# code that I want to convert to T-SQL:
var enumerator = distinctlist.GetEnumerator();
while (enumerator.MoveNext())
{
mtbn dtb = enumerator.Current as mtbn;
var user = users.Where(x => x.Name == dtb.UserNameTb).FirstOrDefault();
var action = actions.Where(x => x.Name == dtb.ActionTb.Value.ToString()).FirstOrDefault();
var project = projects.Where(x => x.Name == dtb.ProjectNameTb).FirstOrDefault();
var transaction = transactions.Where(x => x.Name == dtb.TransactioNameTb).FirstOrDefault();
TransactBoard transactBoard = dbContext.TransactBoard.Add(new TransactBoard
{
User = user != null ? user : new EF.User { Name = dtb.UserNameTb },
Action = action != null ? action : new EF.Action { Name = dtb.ActionTb.Value.ToString() },
Project = project != null ? project : new Project { Name = dtb.ProjectNameTb, Path = #"S:\\xxxx\\" + dtb.ProjectNameTb },
Transaction = transaction != null ? transaction : new Transaction { Name = dtb.TransactioNameTb },
DateTime = dtb.WriteDateTimeTb.Value
});
dbContext.MonitorControl.Add(
new MonitorControl
{
ElementId = dtb.ElementIdTb.Value,
Category = category.Where(x => x.Id == dtb.CategoryIdTb).FirstOrDefault(),
TransactBoard = transactBoard
});
}
This is what I did on T-SQL:
begin tran
insert dbo.TransactionBoard(TrancationId, UserId, ActionId, ProjectId, [DateTime] )
select t.Id as TrancationId, u.Id as UserId, s.ActionTb, p.Id as ProjectId, s.WriteDateTimeTb
from monitorControlDb.dbo.MonitorlControlTable s
left join dbo.[Transaction] t
on t.[Name] = s.TransactioNameTb
left join dbo.[User] u
on u.[Name] = s.UserNameTb
left join dbo.Project p
on p.[Name] = s.ProjectNameTb
insert dbo.MonitorControl(ElementId, CategoryId)
select s.ElementIdTb, s.CategoryIdTb
from monitorControlDb.dbo.MonitorlControlTable s
commit

FATAL_ERROR|System.LimitException: Too many SOQL queries: 201

I am getting too many SOQL queries 201 error in apex class
I tried to check the no of queries within loop
Below is exact error -
11:48:43.9 (2785518121)|FATAL_ERROR|System.LimitException: Too many SOQL queries: 201
Class.GEN_CalculateActToWinScores.calcUserEligible: line 1343, column 1
Class.GEN_ActonFactsScoreUserEligibleBatch.execute: line 74, column 1
11:48:43.9 (2851114444)|CODE_UNIT_FINISHED|GEN_ActonFactsScoreUserEligibleBatch
11:48:43.9 (2852614277)|EXECUTION_FINISHED
Below is the code for method GEN_CalculateActToWinScores.calcUserEligible -
// Method for set user as ready for AoF
public static void calcUserEligible(List<User> usersList ){
List<Act_on_Facts__c> actOnFactDelete = new List<Act_on_Facts__c>();
Set<String> oppOpenStageNameSet = new Set<String>();
oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_IDENTIFY);
oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_QUALIFY);
oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_PROPOSE);
oppOpenStageNameSet.add(GEN_Constants.OPPORTUNITY_NEGOTIATE);
Set<String> oppReadOnlyRecordTypeNameSet = new Set<String>();
oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_SINGLE_ACCOUNT_OPP_RECORDTYPENAME);
oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_WON_AND_DONE_OPP_RECORDTYPENAME);
oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_CHILD_OPP_RECORDTYPENAME);
oppReadOnlyRecordTypeNameSet.add(GEN_Constants.READONLY_MULTI_ACCOUNT_OPP_RECORDTYPENAME);
if(usersList.size() > 0){
List<Id> idList = new List<Id>();
Integer countResult = 0;
List<User> newUserList = new List<User>();
Integer limitQuery; //10000 //2001
Integer limitResult; //2000
if(CSL_ActOnFactsLimits__c.getValues('QUERY_LIMIT') != null){
limitQuery = Integer.valueOf(CSL_ActOnFactsLimits__c.getValues('QUERY_LIMIT').Value__c);
}
if(CSL_ActOnFactsLimits__c.getValues('MAX_QUERY_RESULTS') != null){
limitResult = Integer.valueOf(CSL_ActOnFactsLimits__c.getValues('MAX_QUERY_RESULTS').Value__c);
}
Boolean eligible = true;
for (User userElement : usersList){
String logDetail = ' QUERY_LIMIT:limitQuery: '+limitQuery+' MAX_QUERY_RESULTS:limitResult: '+limitResult;
logDetail += ' userElement.id: '+userElement.id;
eligible = true;
CSH_ActOnFacts_UserEligible__c userEligible = null;
if(CSH_ActOnFacts_UserEligible__c.getValues(userElement.id) != null){
userEligible = CSH_ActOnFacts_UserEligible__c.getValues(userElement.id);
}
CSH_ActOnFacts_UserEligible__c profileEligible = null;
if(CSH_ActOnFacts_UserEligible__c.getValues(userElement.ProfileId) != null){
profileEligible = CSH_ActOnFacts_UserEligible__c.getValues(userElement.ProfileId);
}
List<Act_on_Facts__c> actonfacts = [select id from Act_on_Facts__c where Lookup_User__c = : userElement.id limit 1];
if(userElement.ManagerId == null){
userElement.Line_Manager_Optional__c = true;
userElement.Act_On_Facts_Manager_List__c = null;
}
if(userElement.Default_Macro_Segment__c == null){
userElement.Default_Macro_Segment__c = 'None';
}
if (userElement.IsActive == false){
eligible = false;
}else if(profileEligible != null || userEligible != null) {
eligible = false;
}else{
countResult = [select count() from Account WHERE OwnerId = :userElement.id LIMIT :limitQuery];
logDetail += ' Account.countResult: '+countResult;
if(countResult!=null && countResult > limitResult ){
eligible = false;
}
if(eligible){
if(oppOpenStageNameSet !=null && oppOpenStageNameSet.size()>0 && oppReadOnlyRecordTypeNameSet !=null && oppReadOnlyRecordTypeNameSet.size()>0){
countResult = [select count() from Opportunity WHERE OwnerId = :userElement.id AND StageName IN:oppOpenStageNameSet AND RecordType.DeveloperName NOT IN: oppReadOnlyRecordTypeNameSet LIMIT :limitQuery];
logDetail += ' Opportunity.countResult: '+countResult;
if(countResult!=null && countResult > limitResult ){
eligible = false;
}
}
}
}
if(!eligible){
userElement.Act_on_Facts_Eligible__c = false;
// remove user from Act on Facts
if(actonfacts != null && actonfacts.size()>0){
for(Act_on_Facts__c a : actonfacts){
actOnFactDelete.add(a);
}
}
}else{
userElement.Act_on_Facts_Eligible__c = true;
}
logDetail += ' userElement.Act_on_Facts_Eligible__c: '+userElement.Act_on_Facts_Eligible__c;
ApplicationLog.logEntry(ApplicationLog.SEVERITY_INFO, 'A2WBatch', 'GEN_ActonFactsScoreUserEligibleBatch:'+userElement.id+': ', logDetail);
newUserList.add(userElement);
}
try{
if(newUserList.size()>0){
update newUserList;
system.debug('HC Update- newUserList ' + newUserList);
}
if(actOnFactDelete.size()>0){
delete actOnFactDelete;
system.debug('HC Update- actOnFactDelete ' + actOnFactDelete);
}
}catch (Exception e){
system.debug('Error updating user ' + e);
}
}
}
Code for GEN_ActonFactsScoreUserEligibleBatch.execute-
global void execute(Database.BatchableContext BC, List<sObject> scope){
CSH_A2W_Settings__c a2wCS = CSH_A2W_Settings__c.getInstance();
if(scope != null){
List<User> userList = scope;
if(userList.size()>0){
if(CSL_ActOnFactsLimits__c.getValues('run_userTrigger') != null){
CSL_ActOnFactsLimits__c run_userTrigger = CSL_ActOnFactsLimits__c.getValues('run_userTrigger');
run_userTrigger.Value__c = 'false';
update run_userTrigger;
}
//GEN_CalculateActOnFactsScores.calcUserEligible(userList); //Commented as part of Decommission activity of AoF
if(a2wCS != null && a2wCS.Enabled_in_Batches__c == True){
GEN_CalculateActToWinScores.calcUserEligible(userList);
}
}
}
}
I am trying to analysis what will be the best possible ways to remove these errors or is there any alternate way to implement the same.
All these are queries in a loop:
for (User userElement : usersList){
...
List<Act_on_Facts__c> actonfacts = [select id from Act_on_Facts__c where Lookup_User__c = : userElement.id limit 1];
...
countResult = [select count() from Account WHERE OwnerId = :userElement.id LIMIT :limitQuery];
...
[select count() from Opportunity WHERE OwnerId = :userElement.id AND StageName IN:oppOpenStageNameSet AND RecordType.DeveloperName NOT IN: oppReadOnlyRecordTypeNameSet LIMIT :limitQuery];
As a very quick & dirty solution you can change the batch's size (how many records are passed to each execute). Default is 200.
Call your class with optional parameter Database.executeBatch(new GEN_ActonFactsScoreUserEligibleBatch(), 10); and see if it helps.
"Proper" fix would require some restructuring, taking queries out of the loop, maybe using some Maps where user's id is the key...
If these were custom objects a "pro" Apex developer would cheat, make these queries in one go, pulling user and related lists, something like
SELECT Id,
(SELECT Id FROM Accounts__r LIMIT 1),
(SELECT Id FROM Opportunities__r WHERE ... LIMIT 1),
(SELECT Id FROM Act_On_Facts__r)
FROM User
WHERE Id IN :scope
This won't work here because relation from Account to owner doesn't have a nice name ("Accounts" won't work). You should be still able to do it on the custom object (last subquery in my example, you can call it outside of the loop)
You might still be able to pull something like that off but it'd probably require looking at sharing-related tables... I'd say doable but if you have time to play with it. If you don't - change scope size and call it a day. Will execute bit longer but 1-liner fix is a win in my book.