-
ChatterFeed
-
0Best Answers
-
0Likes Received
-
0Likes Given
-
27Questions
-
24Replies
Test class getting System.JSONException: Malformed JSON: Expected '[' at the beginning of List/Set Error
Hello Everyone,
I have written a trigger and handler class (which uses a future method) and it works well. I am really struggling to write the test class for it. My first problem is that the code coverage is high (before tweaks it was 0% in the handler class). After tweaking, I am getting the following error:
System.JSONException: Malformed JSON: Expected '[' at the beginning of List/Set
I am not sure how to solve this and I am a pretty new dev so not sure what to do next . Can someone please help?
Here is my code:
Trigger:
trigger AccountTriggerKeepAcctTeam on Account (before update) {
List<AccountTeamMember> listAcc = [SELECT Id, AccountAccessLevel, AccountId, CaseAccessLevel, UserId, ContactAccessLevel, OpportunityAccessLevel, TeamMemberRole, PhotoUrl, Title FROM AccountTeamMember Where AccountId in : Trigger.new AND TeamMemberRole != 'Account Executive'];
for(Account acc: Trigger.new){
Account oldAccount = Trigger.oldMap.get(acc.Id);
if(acc.OwnerId != oldAccount.OwnerId){
system.debug('AccountTeamMember records: '+(JSON.serialize(listAcc)));
String str = JSON.serialize(listAcc);
//delete team member records if required
AccountTriggerKeepAcctTeamHandler.retainOldTeamMemberOnOwnerChange(str);
}
}
}
Handler:
public class AccountTriggerKeepAcctTeamHandler {
@future
public static void retainOldTeamMemberOnOwnerChange(String str){
system.debug('Future call '+str);
List<AccountTeamMember> newlistAcc = (List<AccountTeamMember>) JSON.deserialize(str,List<AccountTeamMember>.class);
for(AccountTeamMember objAccTeamMember : newlistAcc){
objAccTeamMember.Id= null;
}
system.debug('Account records to insert'+(JSON.serialize(newlistAcc)));
Upsert newlistAcc;
}
}
Test class:
@isTest
public class AccountTriggerKeepAcctTeamTest {
//@TestSetup
static testMethod void AcctOwnerChange(){
List<User> userList = TestDataFactory.createUser(true, 2);
Profile p = [SELECT Id FROM Profile WHERE Name='System Administrator'];
User u1 = new User(Alias = 'standt', Email='standarduser@testorg1.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testorg01.com');
insert u1;
User u2 = new User(Alias = 'standt', Email='standarduser@testorg2.com',
EmailEncodingKey='UTF-8', LastName='Testing2', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testorg92.com');
insert u2;
System.runAs(u1){
Allowed_Account_Owner_Change__c setting = new Allowed_Account_Owner_Change__c();
setting.Allowed_to_change_Account_Owner__c = true;
insert setting;
fferpcore__ExchangeRateGroup__c exrg = new fferpcore__ExchangeRateGroup__c(CurrencyISOCode = 'USD', fferpcore__DefaultCurrency__c = 'USD - U.S. Dollar', Name = 'FF Shared Test Group', fferpcore__SelectedCurrencies__c = 'USD - U.S. Dollar');
insert exrg;
c2g__codaCompany__c company = new c2g__codaCompany__c();
company.Name = 'ApexTestCompany';
company.RecordTypeId = Schema.SObjectType.c2g__codaCompany__c.RecordTypeInfosByName.get('SUT').RecordTypeId;
insert company;
company.c2g__ExchangeRateGroup__c = exrg.Id;
update company;
Account acc = new Account(Name = 'Test Acc2', NumberOfEmployees = 500);//TestDataFactory.createAccountwithCurrencyMaster(true);
acc.OwnerId = userinfo.getUserId();
insert acc;
AccountTeamMember accTeam = new AccountTeamMember();
accTeam.UserId = acc.OwnerId;
accTeam.AccountAccessLevel = 'Read';
accTeam.AccountId = acc.Id;
insert accTeam;
System.debug('## User '+userinfo.getUserName());
//create opportunity
//}
// }
// static testMethod void testAcctOwnerChange(){
// User u = [Select id, LastName from User where LastName = 'Testing2'];
// Account acc = [Select id, OwnerId from Account Limit 1];
Test.startTest();
acc.OwnerId = u2.id;
update acc;
AccountTriggerKeepAcctTeamHandler.retainOldTeamMemberOnOwnerChange(JSON.serialize(acc));
//System.assertEquals(accTeam.UserId,u2.Id);
Test.stopTest();
//AccountTeamMember atm = [Select userId,AccountId, AccountAccessLevel from AccountTeamMember where AccountId =: acc.Id];
}
}
I have written a trigger and handler class (which uses a future method) and it works well. I am really struggling to write the test class for it. My first problem is that the code coverage is high (before tweaks it was 0% in the handler class). After tweaking, I am getting the following error:
System.JSONException: Malformed JSON: Expected '[' at the beginning of List/Set
I am not sure how to solve this and I am a pretty new dev so not sure what to do next . Can someone please help?
Here is my code:
Trigger:
trigger AccountTriggerKeepAcctTeam on Account (before update) {
List<AccountTeamMember> listAcc = [SELECT Id, AccountAccessLevel, AccountId, CaseAccessLevel, UserId, ContactAccessLevel, OpportunityAccessLevel, TeamMemberRole, PhotoUrl, Title FROM AccountTeamMember Where AccountId in : Trigger.new AND TeamMemberRole != 'Account Executive'];
for(Account acc: Trigger.new){
Account oldAccount = Trigger.oldMap.get(acc.Id);
if(acc.OwnerId != oldAccount.OwnerId){
system.debug('AccountTeamMember records: '+(JSON.serialize(listAcc)));
String str = JSON.serialize(listAcc);
//delete team member records if required
AccountTriggerKeepAcctTeamHandler.retainOldTeamMemberOnOwnerChange(str);
}
}
}
Handler:
public class AccountTriggerKeepAcctTeamHandler {
@future
public static void retainOldTeamMemberOnOwnerChange(String str){
system.debug('Future call '+str);
List<AccountTeamMember> newlistAcc = (List<AccountTeamMember>) JSON.deserialize(str,List<AccountTeamMember>.class);
for(AccountTeamMember objAccTeamMember : newlistAcc){
objAccTeamMember.Id= null;
}
system.debug('Account records to insert'+(JSON.serialize(newlistAcc)));
Upsert newlistAcc;
}
}
Test class:
@isTest
public class AccountTriggerKeepAcctTeamTest {
//@TestSetup
static testMethod void AcctOwnerChange(){
List<User> userList = TestDataFactory.createUser(true, 2);
Profile p = [SELECT Id FROM Profile WHERE Name='System Administrator'];
User u1 = new User(Alias = 'standt', Email='standarduser@testorg1.com',
EmailEncodingKey='UTF-8', LastName='Testing', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testorg01.com');
insert u1;
User u2 = new User(Alias = 'standt', Email='standarduser@testorg2.com',
EmailEncodingKey='UTF-8', LastName='Testing2', LanguageLocaleKey='en_US',
LocaleSidKey='en_US', ProfileId = p.Id,
TimeZoneSidKey='America/Los_Angeles', UserName='standarduser@testorg92.com');
insert u2;
System.runAs(u1){
Allowed_Account_Owner_Change__c setting = new Allowed_Account_Owner_Change__c();
setting.Allowed_to_change_Account_Owner__c = true;
insert setting;
fferpcore__ExchangeRateGroup__c exrg = new fferpcore__ExchangeRateGroup__c(CurrencyISOCode = 'USD', fferpcore__DefaultCurrency__c = 'USD - U.S. Dollar', Name = 'FF Shared Test Group', fferpcore__SelectedCurrencies__c = 'USD - U.S. Dollar');
insert exrg;
c2g__codaCompany__c company = new c2g__codaCompany__c();
company.Name = 'ApexTestCompany';
company.RecordTypeId = Schema.SObjectType.c2g__codaCompany__c.RecordTypeInfosByName.get('SUT').RecordTypeId;
insert company;
company.c2g__ExchangeRateGroup__c = exrg.Id;
update company;
Account acc = new Account(Name = 'Test Acc2', NumberOfEmployees = 500);//TestDataFactory.createAccountwithCurrencyMaster(true);
acc.OwnerId = userinfo.getUserId();
insert acc;
AccountTeamMember accTeam = new AccountTeamMember();
accTeam.UserId = acc.OwnerId;
accTeam.AccountAccessLevel = 'Read';
accTeam.AccountId = acc.Id;
insert accTeam;
System.debug('## User '+userinfo.getUserName());
//create opportunity
//}
// }
// static testMethod void testAcctOwnerChange(){
// User u = [Select id, LastName from User where LastName = 'Testing2'];
// Account acc = [Select id, OwnerId from Account Limit 1];
Test.startTest();
acc.OwnerId = u2.id;
update acc;
AccountTriggerKeepAcctTeamHandler.retainOldTeamMemberOnOwnerChange(JSON.serialize(acc));
//System.assertEquals(accTeam.UserId,u2.Id);
Test.stopTest();
//AccountTeamMember atm = [Select userId,AccountId, AccountAccessLevel from AccountTeamMember where AccountId =: acc.Id];
}
}
- Afzaal Hassan
- June 24, 2021
- Like
- 0
Process Builder fails when putting an apex code in the comment field
I have a Process Builder where if you add a comment on a "Response" ield in the Case-Comment object then it takes that comment and updates the "New Comment" field in the Case object. This PB was working fine until we hit one scenario. Just a background, this object is basically our way of communicating with out customers and helping them with any developer related issues they may have. In this particular scenario, a customer had a coding related problem, so I tried sending him some apex code. When I pasted the apex code in the "Response" field, the PB failed. It keeps on giving me vague errors "We can't save this record because the "Case Comment: Update Case Fields" process failed. Give your Salesforce admin these details. <b>An unhandled fault has occurred in this flow</b><br>An unhandled fault has occurred while processing the flow. Please contact your system administrator for more information. Error ID: 1557112563-28907 (-630144534). The debug logs doesnt help either. It works for every other comment I am making, but when I put apex code such as this:
<apex:outputPanel rendered="
{!salesInvoice.c2g__Dimension2__r.Logo_URL__c != ''}
">
<apex:image URL="
{!salesInvoice.c2g__Dimension2__r.Logo_URL__c}
"/>
</apex:outputPanel>
it fails! I have tried putting quotes around it, tried converting to a Lightning flow, but nothing works. Can someone please help?
Thank you
<apex:outputPanel rendered="
{!salesInvoice.c2g__Dimension2__r.Logo_URL__c != ''}
">
<apex:image URL="
{!salesInvoice.c2g__Dimension2__r.Logo_URL__c}
"/>
</apex:outputPanel>
it fails! I have tried putting quotes around it, tried converting to a Lightning flow, but nothing works. Can someone please help?
Thank you
- Afzaal Hassan
- February 09, 2021
- Like
- 0
How to convert Aura into a LWC JS code
I have a LWC code where if you click the button it generates a URL and then opens it. I have another aura component that is launched from a flow and it does the exact same thing as the LWC but this actually works and the LWC is not working. I was wondering if anyone could help me on how to rewrite the aura controller code as a LWC JS code? Here is the working aura code:
Component:
<aura:component implements="force:lightningQuickAction,lightning:availableForFlowActions">
<aura:attribute name="URLpassing" type="String"/> </aura:component>
JS cONTROLLER:
({
invoke : function(component, event, helper)
var URL = component.get("v.URLpassing");
var redirect = $A.get("e.force:navigateToURL");
// Pass the record ID to the event
redirect.setParams({ "url": URL, });
// Open the record
redirect.fire(); } })
The url is passed from a flow to this aura component
I want to replicate the controller code into my LWC JS so it behaves the same way. This is what my Lwc is doing:
HTML:
<template>
<div>
<lightning-button class="aButton" label="URLCreator" onclick={UrlCreator}>
</lightning-button>
</div> </template>
JS:
export default class URLCreate extends NavigationMixin(LightningElement) {
@api recordId;
@api accId;
@track PageUrl;
URLCreator(event) {
this.PageUrl = '/apex/AVFpage_HTML';
this.PageUrl += "&accountId="+ this.accId; this[NavigationMixin.GenerateUrl]
({ type: 'standard__webPage',
attributes: { url: this.PageUrl } }).then(generatedUrl => {
//this set of code I dont think is working. I need to replicate this like my aura controller code
sforce.one.navigateToUrl(generatedUrl); });
}
If anymore can help, that would create. Again, since my aura is working, I would like to mimic the functionality/code into my LWC but I dont know how to write that aura functionality as LWC Thank you
Component:
<aura:component implements="force:lightningQuickAction,lightning:availableForFlowActions">
<aura:attribute name="URLpassing" type="String"/> </aura:component>
JS cONTROLLER:
({
invoke : function(component, event, helper)
var URL = component.get("v.URLpassing");
var redirect = $A.get("e.force:navigateToURL");
// Pass the record ID to the event
redirect.setParams({ "url": URL, });
// Open the record
redirect.fire(); } })
The url is passed from a flow to this aura component
I want to replicate the controller code into my LWC JS so it behaves the same way. This is what my Lwc is doing:
HTML:
<template>
<div>
<lightning-button class="aButton" label="URLCreator" onclick={UrlCreator}>
</lightning-button>
</div> </template>
JS:
export default class URLCreate extends NavigationMixin(LightningElement) {
@api recordId;
@api accId;
@track PageUrl;
URLCreator(event) {
this.PageUrl = '/apex/AVFpage_HTML';
this.PageUrl += "&accountId="+ this.accId; this[NavigationMixin.GenerateUrl]
({ type: 'standard__webPage',
attributes: { url: this.PageUrl } }).then(generatedUrl => {
//this set of code I dont think is working. I need to replicate this like my aura controller code
sforce.one.navigateToUrl(generatedUrl); });
}
If anymore can help, that would create. Again, since my aura is working, I would like to mimic the functionality/code into my LWC but I dont know how to write that aura functionality as LWC Thank you
- Afzaal Hassan
- November 09, 2020
- Like
- 0
APEX CPU LIMIT how do I use Maps ?
I have created a flow that based on some requirements, finds a list of accounts. The flow then passes this list of accounts and a new account owner (id) to an apex class. The apex class then updates all the accounts with this new owner and also updates each opportunity and each task listed under each activity with the same account owner. This was working fine till I stated updated large number of accounts. I am now hitting APEX CPU Limit. My apex class is shown below. I think I need to use Maps, but I dont know how to. Any ideas on how to rewrite this code to make it more efficient so that I dont run into APEX CPU limits? Thank you
public class LCD_AccountinCounty { @InvocableMethod(label='Account Owner Update flow' Description='Update Account Object with new owner')
public static void updateAccountOwner(List<FlowDetail> flowdetails) { List<Account> accList = new List<Account>();
for(FlowDetail fd : flowdetails){
for(Account acct : fd.accounts){
acct.OwnerId = fd.newAccountOwnerName;
acc.Salesperson__c = SalespersonName;
accList.add(acct);
}
}
update accList;
List<Opportunity> opportunities = new List<Opportunity>(); for(Opportunity opp: [SELECT Id, OwnerId, AccountId, Account.OwnerId FROM Opportunity WHERE AccountId IN :accList and StageName !='Closed']){
opp.OwnerId = opp.Account.OwnerId;
opportunities.add(opp);
}
update opportunities;
List<Task> activities = new List<Task>();
for(Task t: [SELECT Id, OwnerId, WhatId, Account.OwnerId FROM Task WHERE WhatId IN :accList]){
t.OwnerId = t.Account.OwnerId; activities.add(t);
}
update activities;
}
public with sharing class FlowDetail{
@InvocableVariable
public List<Account> accounts;
@InvocableVariable
public String newAccountOwnerName;
@InvocableVariable
public String SalespersonName;
}
}
public class LCD_AccountinCounty { @InvocableMethod(label='Account Owner Update flow' Description='Update Account Object with new owner')
public static void updateAccountOwner(List<FlowDetail> flowdetails) { List<Account> accList = new List<Account>();
for(FlowDetail fd : flowdetails){
for(Account acct : fd.accounts){
acct.OwnerId = fd.newAccountOwnerName;
acc.Salesperson__c = SalespersonName;
accList.add(acct);
}
}
update accList;
List<Opportunity> opportunities = new List<Opportunity>(); for(Opportunity opp: [SELECT Id, OwnerId, AccountId, Account.OwnerId FROM Opportunity WHERE AccountId IN :accList and StageName !='Closed']){
opp.OwnerId = opp.Account.OwnerId;
opportunities.add(opp);
}
update opportunities;
List<Task> activities = new List<Task>();
for(Task t: [SELECT Id, OwnerId, WhatId, Account.OwnerId FROM Task WHERE WhatId IN :accList]){
t.OwnerId = t.Account.OwnerId; activities.add(t);
}
update activities;
}
public with sharing class FlowDetail{
@InvocableVariable
public List<Account> accounts;
@InvocableVariable
public String newAccountOwnerName;
@InvocableVariable
public String SalespersonName;
}
}
- Afzaal Hassan
- December 05, 2019
- Like
- 0
Update a given list and its child objects
Hello,
I have created a lightning flow where I have gotten a list of accounts based on criteria/information input by a user. I am trying to take this list of accounts and update its owner values and all the child contacts for eac account in the list. So it is a list within a list. I know I have to use map for it but I am not sure what I am doing wrong/how to get started. Here is what I have:
public with sharing class LPP_UpdateOwner {
public static void updateAccountOwner(List<List<Account>> accounts, newName){ //accounts would be the input list from the flow and is a list/colection of accounts that the flow queried. newName would be the name the user typed in the flow
List<Account> aUpdated = new List<Account>(); //should this be a map??
for( Account a: accounts){
a.AccountOwner__c = newName;
aUpdated.add(a)
}
update aUpdated;
Map<Id, Opportunity> oppList = new Map<Id, Opportunity>([SELECT Id, Name from Opportunity where AccoundId IN :accounts.keySet() and Stage !='Closed Won']);
List<Opportunity> oppToUpdate = new Opportunity();
for (Opportunity opp :oppList.values()){
opp.OwnerId = account.ownerId ? not sure what to put here
oppToUpdate.add(opp);
}
update OpptoUpdate;
So I am not sure if this is correct or not. Basically, I am trying to update all te accounts and each account's opportunity with a new name thats provided. Also, The reason why I am trying to use Maps is to avoid CPU Time limit because doing this in flow and process builder is casuing CPU time out errors.
Thank you
I have created a lightning flow where I have gotten a list of accounts based on criteria/information input by a user. I am trying to take this list of accounts and update its owner values and all the child contacts for eac account in the list. So it is a list within a list. I know I have to use map for it but I am not sure what I am doing wrong/how to get started. Here is what I have:
public with sharing class LPP_UpdateOwner {
public static void updateAccountOwner(List<List<Account>> accounts, newName){ //accounts would be the input list from the flow and is a list/colection of accounts that the flow queried. newName would be the name the user typed in the flow
List<Account> aUpdated = new List<Account>(); //should this be a map??
for( Account a: accounts){
a.AccountOwner__c = newName;
aUpdated.add(a)
}
update aUpdated;
Map<Id, Opportunity> oppList = new Map<Id, Opportunity>([SELECT Id, Name from Opportunity where AccoundId IN :accounts.keySet() and Stage !='Closed Won']);
List<Opportunity> oppToUpdate = new Opportunity();
for (Opportunity opp :oppList.values()){
opp.OwnerId = account.ownerId ? not sure what to put here
oppToUpdate.add(opp);
}
update OpptoUpdate;
So I am not sure if this is correct or not. Basically, I am trying to update all te accounts and each account's opportunity with a new name thats provided. Also, The reason why I am trying to use Maps is to avoid CPU Time limit because doing this in flow and process builder is casuing CPU time out errors.
Thank you
- Afzaal Hassan
- December 03, 2019
- Like
- 0
getting apex:page error
Hello
I am trying to create a visualforce component but I keep on getting the following error:
<apex:page> is required and must be the outermost tag in the markup at line 1 column 1
I am not sure what I am doing wrong. Here is my component code(IncludeAttachment.vf):
<apex:component controller="LCD_IncludeAttachmentsController" access="global">
<apex:attribute name="opportunityId"
description="Opportunity Id"
assignTo="{!opportunityObjectId}"
type="Id" />
<apex:outputText value="{!PageContents}" escape="false" />
</apex:component>
I went to setup and clicked classic email template. I create a template and inclded the following:
<messaging:emailTemplate subject="Invoice Attached" recipientType="Opportunity" relatedToType="Opportunity" replyTo="your@company.com"> <messaging:attachment renderAs="PDF" filename="Invoice.pdf"> <c:IncludeAttachments contactId="{!relatedTo.Id}"/> </messaging:attachment> <messaging:htmlEmailBody > <html xmlns="http://www.w3.org/1999/xhtml"> Please find your invoice attached. </html> </messaging:emailTemplate>
So I am calling the component and therefore I dont understand what tag I need to use to wrap the actual component. I keep on getting that error on the IncludeAttachment vf page. When I wrap that around apex:page, i get another saying i cant use apex:component. Can someone please help. If you need to see the controller, I can include that too.
Thank you
I am trying to create a visualforce component but I keep on getting the following error:
<apex:page> is required and must be the outermost tag in the markup at line 1 column 1
I am not sure what I am doing wrong. Here is my component code(IncludeAttachment.vf):
<apex:component controller="LCD_IncludeAttachmentsController" access="global">
<apex:attribute name="opportunityId"
description="Opportunity Id"
assignTo="{!opportunityObjectId}"
type="Id" />
<apex:outputText value="{!PageContents}" escape="false" />
</apex:component>
I went to setup and clicked classic email template. I create a template and inclded the following:
<messaging:emailTemplate subject="Invoice Attached" recipientType="Opportunity" relatedToType="Opportunity" replyTo="your@company.com"> <messaging:attachment renderAs="PDF" filename="Invoice.pdf"> <c:IncludeAttachments contactId="{!relatedTo.Id}"/> </messaging:attachment> <messaging:htmlEmailBody > <html xmlns="http://www.w3.org/1999/xhtml"> Please find your invoice attached. </html> </messaging:emailTemplate>
So I am calling the component and therefore I dont understand what tag I need to use to wrap the actual component. I keep on getting that error on the IncludeAttachment vf page. When I wrap that around apex:page, i get another saying i cant use apex:component. Can someone please help. If you need to see the controller, I can include that too.
Thank you
- Afzaal Hassan
- November 26, 2019
- Like
- 0
Parse JSON response in LWC component
Hello
I recently integrated a telephony system into Salesforce. I created a LWC component where a user would inout some values and pass it onto the JS for some processing and then the JS would give a message along with a "processing id." I have everything working except for the last part. I need to create another field in the LWC component that would populate the "message" field and also populate the "processing id" field. These fields should only show when they are available(returned by JS). The JS gives a JSON response and it is in this format:
{
"type": "message",
"message": "Payment Approved with Order Number: &&Secure.OrderNum&& and Processing ID: &&Secure.ProcessID&&"
}
so the processing id is within in the JSON message object. Can you please let me know how I should modify the JS and LWC html to pass and display this?
HTML:
<template>
<lightning-card title="Secure Payment System" icon-name="custom:custom17">
<div class="slds-m-around_medium">
<lightning-input type="number" name="paymentAmount" required label="Order Amount" value="12.34" placeholder="Enter the amount of the transaction" formatter="currency" step="0.01"></lightning-input>
<lightning-input pattern="[0-9]{5}" name="invoiceNumber" label="Order Number" value="12345" placeholder="Enter the 5 digit invoice number"></lightning-input>
<div>
Processing Number: {processingId}
</div>
<div>
Status: {message}
</div>
<br>
<lightning-button label="Transfer to Secure Pay" variant="brand" title="Start with Events" onclick={startSecurePaymentWithEvents} class="slds-m-left_x-small"></lightning-button>
<lightning-
</div>
</lightning-card>
</template>
JS:
/* eslint-disable no-console */
import { LightningElement, api, wire, track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { getRecord } from 'lightning/uiRecordApi';
// These are the Contact Fields that we get and send as cavs
const FIELDS = [
'Case.Contact.FirstName',
'Case.Contact.LastName'
];
const cavBridgeURL = "SecurePay.BridgeURL";
let callVariables;
let self;
export default class SecurePayment extends LightningElement {
bridgeclient = new BridgeClient();
@api objectApiName; // Set by Lightning to the name of the object type
@api recordId; // Set by Lightning to the ID of the object
@track message; //track changes to message so it can be displayed in lwc
// This uses this page's recordID to retrieve the contact's first and last name
@wire(getRecord, { recordId: '$recordId', fields: FIELDS }) case;
get contactFirstName() {
return this.case.contact.data.fields.FirstName.value;
}
get contactLastName() {
return this.case.contact.data.fields.LastName.value;
}
get paymentAmount() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'paymentAmount') {
return inputs[i].value;
}
}
return undefined;
}
get invoiceNumber() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'invoiceNumber') {
return inputs[i].value;
}
}
return undefined;
}
// Our constructor wires in the secpay's callback for the result event
constructor() {
super();
self = this;
secpay.initialize(this._onSecurePaymentStarted);
}
_onOpenEvent(bridgeURL) {
// OK, if we get our URL then we be rolling!
// Lets see if we can send a message to ourselves...
console.log(`WebSocket Opened, Session URL: ${bridgeURL}, initiate secure payment IVR connection`);
// Add the Bridge Server's URL as a CAV.
// The script will use this to send real time messages and any other desired information back to this client
// by POSTing JSON formatted messages to this URL. This URL uniquely identifies this client's session.
callVariables.push({name: cavBridgeURL, value: bridgeURL});
// Now start the secure payment
secpay.startSecurePayment(callVariables);
}
_onDataEvent(jsonData) {
let eventData = JSON.parse(jsonData);
// Is this a message?
if (eventData.type === "message") {
// Yes, show the status
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Status",
message: message,
variant: 'info'
});
dispatchEvent(evt);
}
// Is this a result?
else if (eventData.type === 'result') {
// Yes, show the result
let success = eventData.success;
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Result",
message: message,
variant: success ? 'success' : "error",
url: "www.telephony.com"
});
dispatchEvent(evt);
}
}
_onCloseEvent(error) {
if (error) {
const evt = new ShowToastEvent({
title: "Bridge Event Connection Closed Due to Error",
message: error.message,
variant: "error"
});
dispatchEvent(evt);
}
console.log("WebSocket closed");
}
// Method used to initiate the secure payment
_initiateSecurePayment(withEvents) {
// eslint-disable-next-line no-debugger
debugger;
// Make sure our data is OK
if (!this.paymentAmount || !this.invoiceNumber) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: 'Amount and Invoice fields must both be set',
variant: 'warning'
});
dispatchEvent(evt);
return;
}
//*** Set the CAVs here ***
callVariables = [
{name: 'Secure.OrderNum', value: this.invoiceNumber}, // This comes from the LWC form
{name: 'Secure.PayAmount', value: this.paymentAmount} // This comes from the LWC form
];
/
if (withEvents) {
// We don't know when to close our socket IF we made a sec payment request as we don't get an event when it completes.
if (this.bridgeclient.isOpen()) {
this.bridgeclient.close();
return;
}
// Now kick things off by opening the bridge client. The callbacks will drive us forward and once the socket is open and connected
// we'll go ahead and start the secure payment call process.
try {
// Parms: wsURL, dataEvent, urlEvent, closeEvent
// this.bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent, "ws://localhost:8888/bridge");
this.bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent);
} catch (ex) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: `Failed trying to open connection to event Server: ${ex.message}`,
variant: 'error'
});
dispatchEvent(evt);
}
} else {
secpay.startSecurePayment(callVariables);
}
}
_onSecurePaymentStarted(message, error) {
// Did we get an error?
if (error) {
// If we failed to start the sec pay conference then we need to close the
// Bridge Web Socket if we have a session open
if (self.bridgeclient.isOpen()) {
self.bridgeclient.close();
}
}
const evt = new ShowToastEvent({
title: (error ? "Failure" : "Success"),
message: message,
variant: (error ? 'error' : 'success'),
});
dispatchEvent(evt);
}
// Method used to initiate the secure payment
startSecurePayment() {
this._initiateSecurePayment(false);
}
// Method used to initiate the secure payment with events
startSecurePaymentWithEvents() {
this._initiateSecurePayment(true);
}
}
I think I have not added properly (and dont know how to) take the processid variable that is embedded within the message type in the JSON. Any help, sample code would be great. Thanks
I recently integrated a telephony system into Salesforce. I created a LWC component where a user would inout some values and pass it onto the JS for some processing and then the JS would give a message along with a "processing id." I have everything working except for the last part. I need to create another field in the LWC component that would populate the "message" field and also populate the "processing id" field. These fields should only show when they are available(returned by JS). The JS gives a JSON response and it is in this format:
{
"type": "message",
"message": "Payment Approved with Order Number: &&Secure.OrderNum&& and Processing ID: &&Secure.ProcessID&&"
}
so the processing id is within in the JSON message object. Can you please let me know how I should modify the JS and LWC html to pass and display this?
HTML:
<template>
<lightning-card title="Secure Payment System" icon-name="custom:custom17">
<div class="slds-m-around_medium">
<lightning-input type="number" name="paymentAmount" required label="Order Amount" value="12.34" placeholder="Enter the amount of the transaction" formatter="currency" step="0.01"></lightning-input>
<lightning-input pattern="[0-9]{5}" name="invoiceNumber" label="Order Number" value="12345" placeholder="Enter the 5 digit invoice number"></lightning-input>
<div>
Processing Number: {processingId}
</div>
<div>
Status: {message}
</div>
<br>
<lightning-button label="Transfer to Secure Pay" variant="brand" title="Start with Events" onclick={startSecurePaymentWithEvents} class="slds-m-left_x-small"></lightning-button>
<lightning-
</div>
</lightning-card>
</template>
JS:
/* eslint-disable no-console */
import { LightningElement, api, wire, track } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { getRecord } from 'lightning/uiRecordApi';
// These are the Contact Fields that we get and send as cavs
const FIELDS = [
'Case.Contact.FirstName',
'Case.Contact.LastName'
];
const cavBridgeURL = "SecurePay.BridgeURL";
let callVariables;
let self;
export default class SecurePayment extends LightningElement {
bridgeclient = new BridgeClient();
@api objectApiName; // Set by Lightning to the name of the object type
@api recordId; // Set by Lightning to the ID of the object
@track message; //track changes to message so it can be displayed in lwc
// This uses this page's recordID to retrieve the contact's first and last name
@wire(getRecord, { recordId: '$recordId', fields: FIELDS }) case;
get contactFirstName() {
return this.case.contact.data.fields.FirstName.value;
}
get contactLastName() {
return this.case.contact.data.fields.LastName.value;
}
get paymentAmount() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'paymentAmount') {
return inputs[i].value;
}
}
return undefined;
}
get invoiceNumber() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'invoiceNumber') {
return inputs[i].value;
}
}
return undefined;
}
// Our constructor wires in the secpay's callback for the result event
constructor() {
super();
self = this;
secpay.initialize(this._onSecurePaymentStarted);
}
_onOpenEvent(bridgeURL) {
// OK, if we get our URL then we be rolling!
// Lets see if we can send a message to ourselves...
console.log(`WebSocket Opened, Session URL: ${bridgeURL}, initiate secure payment IVR connection`);
// Add the Bridge Server's URL as a CAV.
// The script will use this to send real time messages and any other desired information back to this client
// by POSTing JSON formatted messages to this URL. This URL uniquely identifies this client's session.
callVariables.push({name: cavBridgeURL, value: bridgeURL});
// Now start the secure payment
secpay.startSecurePayment(callVariables);
}
_onDataEvent(jsonData) {
let eventData = JSON.parse(jsonData);
// Is this a message?
if (eventData.type === "message") {
// Yes, show the status
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Status",
message: message,
variant: 'info'
});
dispatchEvent(evt);
}
// Is this a result?
else if (eventData.type === 'result') {
// Yes, show the result
let success = eventData.success;
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Result",
message: message,
variant: success ? 'success' : "error",
url: "www.telephony.com"
});
dispatchEvent(evt);
}
}
_onCloseEvent(error) {
if (error) {
const evt = new ShowToastEvent({
title: "Bridge Event Connection Closed Due to Error",
message: error.message,
variant: "error"
});
dispatchEvent(evt);
}
console.log("WebSocket closed");
}
// Method used to initiate the secure payment
_initiateSecurePayment(withEvents) {
// eslint-disable-next-line no-debugger
debugger;
// Make sure our data is OK
if (!this.paymentAmount || !this.invoiceNumber) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: 'Amount and Invoice fields must both be set',
variant: 'warning'
});
dispatchEvent(evt);
return;
}
//*** Set the CAVs here ***
callVariables = [
{name: 'Secure.OrderNum', value: this.invoiceNumber}, // This comes from the LWC form
{name: 'Secure.PayAmount', value: this.paymentAmount} // This comes from the LWC form
];
/
if (withEvents) {
// We don't know when to close our socket IF we made a sec payment request as we don't get an event when it completes.
if (this.bridgeclient.isOpen()) {
this.bridgeclient.close();
return;
}
// Now kick things off by opening the bridge client. The callbacks will drive us forward and once the socket is open and connected
// we'll go ahead and start the secure payment call process.
try {
// Parms: wsURL, dataEvent, urlEvent, closeEvent
// this.bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent, "ws://localhost:8888/bridge");
this.bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent);
} catch (ex) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: `Failed trying to open connection to event Server: ${ex.message}`,
variant: 'error'
});
dispatchEvent(evt);
}
} else {
secpay.startSecurePayment(callVariables);
}
}
_onSecurePaymentStarted(message, error) {
// Did we get an error?
if (error) {
// If we failed to start the sec pay conference then we need to close the
// Bridge Web Socket if we have a session open
if (self.bridgeclient.isOpen()) {
self.bridgeclient.close();
}
}
const evt = new ShowToastEvent({
title: (error ? "Failure" : "Success"),
message: message,
variant: (error ? 'error' : 'success'),
});
dispatchEvent(evt);
}
// Method used to initiate the secure payment
startSecurePayment() {
this._initiateSecurePayment(false);
}
// Method used to initiate the secure payment with events
startSecurePaymentWithEvents() {
this._initiateSecurePayment(true);
}
}
I think I have not added properly (and dont know how to) take the processid variable that is embedded within the message type in the JSON. Any help, sample code would be great. Thanks
- Afzaal Hassan
- November 12, 2019
- Like
- 0
Render a Javascript generated barcode as pdf
I am using a JS library called barcode39 to create a barcode image. I already imported the JS library in the static resource and have included the JS in my visualforce page. The barcode is generating fine in the VF page. The problem is I need to render this page as a pdf. When I do that, the barcode image does not appear. I DO NOT want to use the image url from barcodeinc because its very unstable. Can you please let me know what I can do to modify the code below to make the barcode render in pdf as well? Thank you
<apex:page standardController="Opportunity" extensions="LPP_PackingSlip" showHeader="false" sidebar="false" renderAs="pdf" standardStylesheets="false" applyHtmlTag="false">
<apex:includeScript value="{!$Resource.BarcodeScript}"/>
<head>
<body>
<apex:outputText rendered="{!hasPictureDays}">
<!--Header-->
<br/>
<div class="headerSlip">{!Opportunity.Account.Name}</div><br/>
<div class="jobSlip">{!Opportunity.WPA__c}</div>
<center><svg id="barcode"></svg></center>
<br/><br/>
</apex:outputText>
</body>
<script type ="text/javascript">
JsBarcode("#barcode", "{!Opportunity.WPA__c}",{
fontOptions: "both",
font : "OCRB",
textAlign : "center",
Textmargin : 5,
fontSize : 12,
width: 1,
height: 50
});
</script>
</apex:page>
<apex:page standardController="Opportunity" extensions="LPP_PackingSlip" showHeader="false" sidebar="false" renderAs="pdf" standardStylesheets="false" applyHtmlTag="false">
<apex:includeScript value="{!$Resource.BarcodeScript}"/>
<head>
<body>
<apex:outputText rendered="{!hasPictureDays}">
<!--Header-->
<br/>
<div class="headerSlip">{!Opportunity.Account.Name}</div><br/>
<div class="jobSlip">{!Opportunity.WPA__c}</div>
<center><svg id="barcode"></svg></center>
<br/><br/>
</apex:outputText>
</body>
<script type ="text/javascript">
JsBarcode("#barcode", "{!Opportunity.WPA__c}",{
fontOptions: "both",
font : "OCRB",
textAlign : "center",
Textmargin : 5,
fontSize : 12,
width: 1,
height: 50
});
</script>
</apex:page>
- Afzaal Hassan
- October 31, 2019
- Like
- 0
Formatting the JS in a Five9 IVR LWC component
Hello
I am integrating Five9 IVR system into my SF org. Five9 gave me a sample code that is basically an LWC component so that an agen can enter the amount and order number. When I am putting that LWC in a Contact record (in the app builder), its showig up fine. But I actually want to put it in a Case record. When I put it there, the component just shows the title and not the fields. This is probably because the JS file is referencing the contact object. I dont know how to modify this JS so that it shows up in the case record. Also, i have a ContactId in my case object as a field. Here is the JS and HTML file. Thanks
Meta XML file:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="five9SecurePayment">
<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<!-- <target>lightning__HomePage</target> -->
<!-- <target>lightning__AppPage</target> -->
<target>lightning__RecordPage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Case</object> //changed this to Case from contact
</objects>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
HTML file:
<template>
<lightning-card title="Five9 Secure Payment 2.0" icon-name="custom:custom17">
<template if:true={contact.data}>
<div class="slds-m-around_medium">
<!-- <p>{contactName} - <lightning-formatted-phone value={contactPhone}></lightning-formatted-phone></p> -->
<lightning-input type="number" name="paymentAmount" required label="Transaction Amount" value="12.34" placeholder="Enter the amount of the transaction" formatter="currency" step="0.01"></lightning-input>
<lightning-input pattern="[0-9]{5}" name="invoiceNumber" label="Invoice Number" value="12345" placeholder="Enter the 5 digit invoice number"></lightning-input>
<br>
<lightning-button label="Start with Events" variant="brand" title="Start with Events" onclick={startSecurePaymentWithEvents} class="slds-m-left_x-small"></lightning-button>
<lightning-button label="Start" variant="brand" title="Start" onclick={startSecurePayment} class="slds-m-left_x-small"></lightning-button>
<lightning-button label="Cancel" variant="destructive" title="Cancel" onclick={cancelSecurePayment} class="slds-m-left_x-small"></lightning-button>
</div>
</template>
<!-- <template if:true={contact.error}>
<c-error-panel errors={contact.error}></c-error-panel>
</template> -->
</lightning-card>
</template>
JS file:
/* eslint-disable no-console */
import { LightningElement, api, wire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { getRecord } from 'lightning/uiRecordApi';
import * as secpay from './five9secpay';
import { Five9BridgeClient } from './five9bridgeclient';
// These are the Contact Fields that we get and send as cavs
const FIELDS = [
'Contact.FirstName',
'Contact.LastName'
]; // these fields need to change to have case fields i think
// CAV to pass the client's unique Bridge REST request URL.
// NOTE that the IVR must reference the same CAV name.
// Also, any campaigns must add this and any application specific CAVs to their Campaign Profile's Layout in the Five9 Admin
const cavBridgeURL = "SecurePay.BridgeURL";
let callVariables;
let self;
export default class SecurePayment extends LightningElement {
five9bridgeclient = new Five9BridgeClient();
@api objectApiName; // Set by Lightning to the name of the object type
@api recordId; // Set by Lightning to the ID of the object
// This uses this page's recordID to retrieve the contact's first and last name
@wire(getRecord, { recordId: '$recordId', fields: FIELDS }) contact; //should this case instead of contact?
get contactFirstName() {
return this.contact.data.fields.FirstName.value;
}
get contactLastName() {
return this.contact.data.fields.LastName.value;
}//above 2 methd probably need to be modified
get paymentAmount() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'paymentAmount') {
return inputs[i].value;
}
}
return undefined;
}
get invoiceNumber() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'invoiceNumber') {
return inputs[i].value;
}
}
return undefined;
}
// Our constructor wires in the secpay's callback for the result event
constructor() {
super();
self = this;
secpay.initialize(this._onSecurePaymentStarted);
}
_onOpenEvent(bridgeURL) {
// OK, if we get our URL then we be rolling!
// Lets see if we can send a message to ourselves...
console.log(`WebSocket Opened, Session URL: ${bridgeURL}, initiate secure payment IVR connection`);
// Add the Bridge Server's URL as a CAV.
// The script will use this to send real time messages and any other desired information back to this client
// by POSTing JSON formatted messages to this URL. This URL uniquely identifies this client's session.
callVariables.push({name: cavBridgeURL, value: bridgeURL});
// Now start the secure payment
secpay.startSecurePayment(callVariables);
}
_onDataEvent(jsonData) {
let eventData = JSON.parse(jsonData);
// Is this a message?
if (eventData.type === "message") {
// Yes, show the status
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Status",
message: message,
variant: 'info'
});
dispatchEvent(evt);
}
// Is this a result?
else if (eventData.type === 'result') {
// Yes, show the result
let success = eventData.success;
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Result",
message: message,
variant: success ? 'success' : "error",
url: "www.five9.com"
});
dispatchEvent(evt);
}
}
_onCloseEvent(error) {
if (error) {
const evt = new ShowToastEvent({
title: "Bridge Event Connection Closed Due to Error",
message: error.message,
variant: "error"
});
dispatchEvent(evt);
}
console.log("WebSocket closed");
}
// Method used to initiate the secure payment
_initiateSecurePayment(withEvents) {
// eslint-disable-next-line no-debugger
debugger;
// Make sure our data is OK
if (!this.paymentAmount || !this.invoiceNumber) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: 'Amount and Invoice fields must both be set',
variant: 'warning'
});
dispatchEvent(evt);
return;
}
//*** Set the CAVs here ***
callVariables = [
{name: 'SecurePay.FirstName', value: this.contactFirstName}, // This comes from the SF Contact
{name: 'SecurePay.LastName', value: this.contactLastName}, // This comes from the SF Contact. These 2 lines need to be changed
{name: 'SecurePay.InvoiceNumber', value: this.invoiceNumber}, // This comes from the LWC form
{name: 'SecurePay.PaymentAmount', value: this.paymentAmount} // This comes from the LWC form
];
// Are we using the Five9 Bridge Service to get events?
if (withEvents) {
// We don't know when to close our socket IF we made a sec payment request as we don't get an event when it completes.
// So, we always check for and close here if needed. Right now we don't provide any feedback as this would only
// happen if the script didn't send a DELETE at the end of a previous secure payment IVR session which is a defect.
if (this.five9bridgeclient.isOpen()) {
this.five9bridgeclient.close();
return;
}
// Now kick things off by opening the bridge client. The callbacks will drive us forward and once the socket is open and connected
// we'll go ahead and start the secure payment call process.
try {
// Parms: wsURL, dataEvent, urlEvent, closeEvent
// this.five9bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent, "ws://localhost:5555/bridge");
this.five9bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent);
} catch (ex) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: `Failed trying to open connection to event Server: ${ex.message}`,
variant: 'error'
});
dispatchEvent(evt);
}
} else {
secpay.startSecurePayment(callVariables);
}
}
_onSecurePaymentStarted(message, error) {
// Did we get an error?
if (error) {
// If we failed to start the sec pay conference then we need to close the
// Bridge Web Socket if we have a session open
if (self.five9bridgeclient.isOpen()) {
self.five9bridgeclient.close();
}
}
const evt = new ShowToastEvent({
title: (error ? "Failure" : "Success"),
message: message,
variant: (error ? 'error' : 'success'),
});
dispatchEvent(evt);
}
// Method used to initiate the secure payment
startSecurePayment() {
this._initiateSecurePayment(false);
}
// Method used to initiate the secure payment with events
startSecurePaymentWithEvents() {
this._initiateSecurePayment(true);
}
// Method used to cancel an active secure pay IVR session
cancelSecurePayment() {
if (this.five9bridgeclient.isOpen()) {
this.five9bridgeclient.close();
}
secpay.cancelSecurePayment(true);
}
}
There were other JS files in this sample that five9 provided and I can provide that if needed. Please someone help me modify this JS because I cant get his to work on Case. Thanks
I am integrating Five9 IVR system into my SF org. Five9 gave me a sample code that is basically an LWC component so that an agen can enter the amount and order number. When I am putting that LWC in a Contact record (in the app builder), its showig up fine. But I actually want to put it in a Case record. When I put it there, the component just shows the title and not the fields. This is probably because the JS file is referencing the contact object. I dont know how to modify this JS so that it shows up in the case record. Also, i have a ContactId in my case object as a field. Here is the JS and HTML file. Thanks
Meta XML file:
<?xml version="1.0" encoding="UTF-8"?>
<LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata" fqn="five9SecurePayment">
<apiVersion>45.0</apiVersion>
<isExposed>true</isExposed>
<targets>
<!-- <target>lightning__HomePage</target> -->
<!-- <target>lightning__AppPage</target> -->
<target>lightning__RecordPage</target>
</targets>
<targetConfigs>
<targetConfig targets="lightning__RecordPage">
<objects>
<object>Case</object> //changed this to Case from contact
</objects>
</targetConfig>
</targetConfigs>
</LightningComponentBundle>
HTML file:
<template>
<lightning-card title="Five9 Secure Payment 2.0" icon-name="custom:custom17">
<template if:true={contact.data}>
<div class="slds-m-around_medium">
<!-- <p>{contactName} - <lightning-formatted-phone value={contactPhone}></lightning-formatted-phone></p> -->
<lightning-input type="number" name="paymentAmount" required label="Transaction Amount" value="12.34" placeholder="Enter the amount of the transaction" formatter="currency" step="0.01"></lightning-input>
<lightning-input pattern="[0-9]{5}" name="invoiceNumber" label="Invoice Number" value="12345" placeholder="Enter the 5 digit invoice number"></lightning-input>
<br>
<lightning-button label="Start with Events" variant="brand" title="Start with Events" onclick={startSecurePaymentWithEvents} class="slds-m-left_x-small"></lightning-button>
<lightning-button label="Start" variant="brand" title="Start" onclick={startSecurePayment} class="slds-m-left_x-small"></lightning-button>
<lightning-button label="Cancel" variant="destructive" title="Cancel" onclick={cancelSecurePayment} class="slds-m-left_x-small"></lightning-button>
</div>
</template>
<!-- <template if:true={contact.error}>
<c-error-panel errors={contact.error}></c-error-panel>
</template> -->
</lightning-card>
</template>
JS file:
/* eslint-disable no-console */
import { LightningElement, api, wire } from 'lwc';
import { ShowToastEvent } from 'lightning/platformShowToastEvent';
import { getRecord } from 'lightning/uiRecordApi';
import * as secpay from './five9secpay';
import { Five9BridgeClient } from './five9bridgeclient';
// These are the Contact Fields that we get and send as cavs
const FIELDS = [
'Contact.FirstName',
'Contact.LastName'
]; // these fields need to change to have case fields i think
// CAV to pass the client's unique Bridge REST request URL.
// NOTE that the IVR must reference the same CAV name.
// Also, any campaigns must add this and any application specific CAVs to their Campaign Profile's Layout in the Five9 Admin
const cavBridgeURL = "SecurePay.BridgeURL";
let callVariables;
let self;
export default class SecurePayment extends LightningElement {
five9bridgeclient = new Five9BridgeClient();
@api objectApiName; // Set by Lightning to the name of the object type
@api recordId; // Set by Lightning to the ID of the object
// This uses this page's recordID to retrieve the contact's first and last name
@wire(getRecord, { recordId: '$recordId', fields: FIELDS }) contact; //should this case instead of contact?
get contactFirstName() {
return this.contact.data.fields.FirstName.value;
}
get contactLastName() {
return this.contact.data.fields.LastName.value;
}//above 2 methd probably need to be modified
get paymentAmount() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'paymentAmount') {
return inputs[i].value;
}
}
return undefined;
}
get invoiceNumber() {
const inputs = this.template.querySelectorAll('lightning-input');
for (let i = 0; i < inputs.length; i++) {
if (inputs[i].name === 'invoiceNumber') {
return inputs[i].value;
}
}
return undefined;
}
// Our constructor wires in the secpay's callback for the result event
constructor() {
super();
self = this;
secpay.initialize(this._onSecurePaymentStarted);
}
_onOpenEvent(bridgeURL) {
// OK, if we get our URL then we be rolling!
// Lets see if we can send a message to ourselves...
console.log(`WebSocket Opened, Session URL: ${bridgeURL}, initiate secure payment IVR connection`);
// Add the Bridge Server's URL as a CAV.
// The script will use this to send real time messages and any other desired information back to this client
// by POSTing JSON formatted messages to this URL. This URL uniquely identifies this client's session.
callVariables.push({name: cavBridgeURL, value: bridgeURL});
// Now start the secure payment
secpay.startSecurePayment(callVariables);
}
_onDataEvent(jsonData) {
let eventData = JSON.parse(jsonData);
// Is this a message?
if (eventData.type === "message") {
// Yes, show the status
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Status",
message: message,
variant: 'info'
});
dispatchEvent(evt);
}
// Is this a result?
else if (eventData.type === 'result') {
// Yes, show the result
let success = eventData.success;
let message = eventData.message;
const evt = new ShowToastEvent({
title: "Payment Result",
message: message,
variant: success ? 'success' : "error",
url: "www.five9.com"
});
dispatchEvent(evt);
}
}
_onCloseEvent(error) {
if (error) {
const evt = new ShowToastEvent({
title: "Bridge Event Connection Closed Due to Error",
message: error.message,
variant: "error"
});
dispatchEvent(evt);
}
console.log("WebSocket closed");
}
// Method used to initiate the secure payment
_initiateSecurePayment(withEvents) {
// eslint-disable-next-line no-debugger
debugger;
// Make sure our data is OK
if (!this.paymentAmount || !this.invoiceNumber) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: 'Amount and Invoice fields must both be set',
variant: 'warning'
});
dispatchEvent(evt);
return;
}
//*** Set the CAVs here ***
callVariables = [
{name: 'SecurePay.FirstName', value: this.contactFirstName}, // This comes from the SF Contact
{name: 'SecurePay.LastName', value: this.contactLastName}, // This comes from the SF Contact. These 2 lines need to be changed
{name: 'SecurePay.InvoiceNumber', value: this.invoiceNumber}, // This comes from the LWC form
{name: 'SecurePay.PaymentAmount', value: this.paymentAmount} // This comes from the LWC form
];
// Are we using the Five9 Bridge Service to get events?
if (withEvents) {
// We don't know when to close our socket IF we made a sec payment request as we don't get an event when it completes.
// So, we always check for and close here if needed. Right now we don't provide any feedback as this would only
// happen if the script didn't send a DELETE at the end of a previous secure payment IVR session which is a defect.
if (this.five9bridgeclient.isOpen()) {
this.five9bridgeclient.close();
return;
}
// Now kick things off by opening the bridge client. The callbacks will drive us forward and once the socket is open and connected
// we'll go ahead and start the secure payment call process.
try {
// Parms: wsURL, dataEvent, urlEvent, closeEvent
// this.five9bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent, "ws://localhost:5555/bridge");
this.five9bridgeclient.open(this._onDataEvent, this._onOpenEvent, this._onCloseEvent);
} catch (ex) {
const evt = new ShowToastEvent({
title: "Secure Payment",
message: `Failed trying to open connection to event Server: ${ex.message}`,
variant: 'error'
});
dispatchEvent(evt);
}
} else {
secpay.startSecurePayment(callVariables);
}
}
_onSecurePaymentStarted(message, error) {
// Did we get an error?
if (error) {
// If we failed to start the sec pay conference then we need to close the
// Bridge Web Socket if we have a session open
if (self.five9bridgeclient.isOpen()) {
self.five9bridgeclient.close();
}
}
const evt = new ShowToastEvent({
title: (error ? "Failure" : "Success"),
message: message,
variant: (error ? 'error' : 'success'),
});
dispatchEvent(evt);
}
// Method used to initiate the secure payment
startSecurePayment() {
this._initiateSecurePayment(false);
}
// Method used to initiate the secure payment with events
startSecurePaymentWithEvents() {
this._initiateSecurePayment(true);
}
// Method used to cancel an active secure pay IVR session
cancelSecurePayment() {
if (this.five9bridgeclient.isOpen()) {
this.five9bridgeclient.close();
}
secpay.cancelSecurePayment(true);
}
}
There were other JS files in this sample that five9 provided and I can provide that if needed. Please someone help me modify this JS because I cant get his to work on Case. Thanks
- Afzaal Hassan
- October 25, 2019
- Like
- 0
Sharing and Visibility practice exam questions' answers
I have been taking some practice exams online. However, I am getting different correct answers for some of the questions. In other words, some online forums say the answer A, the others B, for example. Can someone provide the correct answer and an explanation for the following:
1)Universal Health is planning to store patient notes in Salesforce. Patient notes consist of long text notes taken by a user to document phone calls with patient. A data audit has identified that these notes can contain Personally Identifiable Information (PII) and Personal Health Information (PHI). The regulatory requirements state that this data must be encrypted at rest as well as in transit. What should the Architect do in order to make sure Universal Health stays compliant?
A.No action is required; all Salesforce data is encrypted at rest as part of Salesforce’s standard trust measures
B.Use an Apex Trigger and the Apex Crypto class to encrypt patient notes as soon as they saved to Salesforce
C.Enable Salesforce Shield Platform Data Encryption and mark the patient notes field as encrypted
D.Create a new Custom Field of type “Text (Encrypted)” and move the patient notes data into the new field
2)Universal Containers (UC) has a requirement to expose a web service to their business partners. The web service will be used to allow each business partner to query UC's Salesforce instance to retrieve the status of orders. The business partner should only be allowed access to orders for which the business partner is the fulfillment vendor. The Architect does not want the business partners to utilize the standard APIs and would prefer a custom API be developed. Which three design elements should the Architect consider in order to ensure the data security of the solution? Choose 3 answers
A.Query the Orders object with Dynamic SOQL based upon the fulfillment ID
B.Provide each partner with their own Salesforce login set to API Enabled on the profile
C.Develop a custom Apex web service with a fulfillment ID input attribute
D.Set the Orders object’s sharing setting to Private in the Org-Wide Defaults
E.Develop a Custom Apex web service using the “With Sharing” keyword
3)In order to comply with regulatory requirements, Universal Health must encrypt all Personally Identifiable Information (PII), both while it is being transmitted over the network and while it is at rest. Universal Health has completed a data audit and has determined that 12 fields on the contact record can contain PII, including the contact name and several other standard fields. Universal Health would like the fields to remain accessible in Salesforce. Which two options does Universal Health have to maintain compliance? Choose 2 answers
A.Use an external, third party encryption service to encrypt PII before it enters Salesforce
B.Enable Salesforce Platform Encryption and select the 12 contact fields to be encrypted
C.Implement a custom Apex trigger to automatically encrypt the PII data using the Apex Crypto Class
D.Update the field type of each of the 12 fields to “Text (Encrypted)” so that they are encrypted at rest
5)Universal Containers has implemented a strict software architecture for their custom Apex code. One of the requirements is that all SOQL queries are contained within reusable classes. Depending on the context of the Apex transaction, the queries should be able to run either "With Sharing" or "Without Sharing". Which two ways allow the Architect to meet these requirements? Choose 2 answers
A.Create a SystemSOQLQueries class and a UserSOQLQueries class; set the “With Sharing” keyword on the UserSOQLQueries class and “Without Sharing” on the SystemSOQLQueries class
B.Create a reusable SOQLQueries class; do not specify “With” or “Without Sharing” on the SOQLQueries class
C.Create a reusable SOQLQueries class; do not specify “With” or “Without Sharing” on the SOQLQueries class and use the runAs () method to dynamically set the context
D.Create a reusable SOQLQueries class; specify “With Sharing” on the methods that require user context and “Without Sharing” on the methods requiring system context
6)Universal Containers has a global 24*7 Salesforce.com implementation that supports Sales, Services, Order Management, and various other parts of their business. They have a nested territory hierarchy, 10,000 sales users, and 20,000 support agents. Territory changes happen daily. The demand for new applications and changes to the platform is high and they follow an agile development methodology and deliver new releases every two weeks on the platform. What Salesforce.com feature would help the system recover from maintenance restart on Salesforce servers?
A.Enable Parallel Sharing Rule recalculation
B.Enable Granular Locking on the system
C.Enable Filter-Based Opportunity Territory Assignment
D.Enable Deferred Sharing Rule recalculation
Thank you
1)Universal Health is planning to store patient notes in Salesforce. Patient notes consist of long text notes taken by a user to document phone calls with patient. A data audit has identified that these notes can contain Personally Identifiable Information (PII) and Personal Health Information (PHI). The regulatory requirements state that this data must be encrypted at rest as well as in transit. What should the Architect do in order to make sure Universal Health stays compliant?
A.No action is required; all Salesforce data is encrypted at rest as part of Salesforce’s standard trust measures
B.Use an Apex Trigger and the Apex Crypto class to encrypt patient notes as soon as they saved to Salesforce
C.Enable Salesforce Shield Platform Data Encryption and mark the patient notes field as encrypted
D.Create a new Custom Field of type “Text (Encrypted)” and move the patient notes data into the new field
2)Universal Containers (UC) has a requirement to expose a web service to their business partners. The web service will be used to allow each business partner to query UC's Salesforce instance to retrieve the status of orders. The business partner should only be allowed access to orders for which the business partner is the fulfillment vendor. The Architect does not want the business partners to utilize the standard APIs and would prefer a custom API be developed. Which three design elements should the Architect consider in order to ensure the data security of the solution? Choose 3 answers
A.Query the Orders object with Dynamic SOQL based upon the fulfillment ID
B.Provide each partner with their own Salesforce login set to API Enabled on the profile
C.Develop a custom Apex web service with a fulfillment ID input attribute
D.Set the Orders object’s sharing setting to Private in the Org-Wide Defaults
E.Develop a Custom Apex web service using the “With Sharing” keyword
3)In order to comply with regulatory requirements, Universal Health must encrypt all Personally Identifiable Information (PII), both while it is being transmitted over the network and while it is at rest. Universal Health has completed a data audit and has determined that 12 fields on the contact record can contain PII, including the contact name and several other standard fields. Universal Health would like the fields to remain accessible in Salesforce. Which two options does Universal Health have to maintain compliance? Choose 2 answers
A.Use an external, third party encryption service to encrypt PII before it enters Salesforce
B.Enable Salesforce Platform Encryption and select the 12 contact fields to be encrypted
C.Implement a custom Apex trigger to automatically encrypt the PII data using the Apex Crypto Class
D.Update the field type of each of the 12 fields to “Text (Encrypted)” so that they are encrypted at rest
5)Universal Containers has implemented a strict software architecture for their custom Apex code. One of the requirements is that all SOQL queries are contained within reusable classes. Depending on the context of the Apex transaction, the queries should be able to run either "With Sharing" or "Without Sharing". Which two ways allow the Architect to meet these requirements? Choose 2 answers
A.Create a SystemSOQLQueries class and a UserSOQLQueries class; set the “With Sharing” keyword on the UserSOQLQueries class and “Without Sharing” on the SystemSOQLQueries class
B.Create a reusable SOQLQueries class; do not specify “With” or “Without Sharing” on the SOQLQueries class
C.Create a reusable SOQLQueries class; do not specify “With” or “Without Sharing” on the SOQLQueries class and use the runAs () method to dynamically set the context
D.Create a reusable SOQLQueries class; specify “With Sharing” on the methods that require user context and “Without Sharing” on the methods requiring system context
6)Universal Containers has a global 24*7 Salesforce.com implementation that supports Sales, Services, Order Management, and various other parts of their business. They have a nested territory hierarchy, 10,000 sales users, and 20,000 support agents. Territory changes happen daily. The demand for new applications and changes to the platform is high and they follow an agile development methodology and deliver new releases every two weeks on the platform. What Salesforce.com feature would help the system recover from maintenance restart on Salesforce servers?
A.Enable Parallel Sharing Rule recalculation
B.Enable Granular Locking on the system
C.Enable Filter-Based Opportunity Territory Assignment
D.Enable Deferred Sharing Rule recalculation
Thank you
- Afzaal Hassan
- October 09, 2019
- Like
- 0
Retrieve Account name from search results in a lightning component
Hello
I am 95% done with writing a Lightning Component. What this app does is when a user types in a phone or name, it lists all the contact records associated with the search result. On of the columns is the account name associated with the contact. It also displays a radio button that you need to select. The only thing I have left to do is the following(and I am struggling to get it working):
If the account name starts with a P and a number, so P0232 - Greenwood, then I dont need to select the radio button. Currently, i have an error message popup when its not selected, which should only happen if the name was just Greenwood, for example. Not sure what to put in the conditional to make this work. Here is my code:
Component:
<div style="font-size: 20px">Customer Information</div>
<table>
<tr style="width: 100%;">
<td>
First Name: <lightning:input name="sFirstName" value="{!v.sFirst}"/>
</td>
<td>
Last Name: <lightning:input name="sLastName" value="{!v.sLast}"/>
</td>
<td>
Phone Number: <lightning:input name="sPhone" value="{!v.ani}"/>
</td>
<td style="vertical-align:bottom;">
<lightning:button label="Search" onclick="{!c.doConSearch}" />
</td>
</tr>
</table>
<br />
<aura:if isTrue="{!v.hasContactResults}">
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
<th>Mobile</th>
<th>Email</th>
<th>Current Account</th>
<th>City</th>
<th>State</th>
<th>Use This Contact</th>
</thead>
<aura:iteration items="{!v.contacts}" var="con">
<tr>
<td>{!con.FirstName}</td>
<td>{!con.LastName}</td>
<td>{!con.Phone}</td>
<td>{!con.MobilePhone}</td>
<td>{!con.Email}</td>
<td>{!con.Account.Name}</td>
<td>{!con.MailingCity}</td>
<td>{!con.MailingState}</td>
<td><ui:inputRadio name="cons" label="{!con.Id}" labelClass="invis" change="{!c.onRadio}" /></td>
</tr>
</aura:iteration>
</table>
</aura:if>
Here is the Controller:
doConSearch : function(component, event, helper) {
helper.searchContacts(component);
component.set("v.selectedCon", "");
helper.searchCases(component);
if(!component.get("v.showAct")){
var a = component.get('c.getCallQueue');
$A.enqueueAction(a);
}
},
createCase : function(component, event, helper) {
component.set("v.hasErrors", false);
component.set("v.errors", "");
var studio = component.get("v.selectedCon");
if(component.get("v.selectedStudio") || component.get("v.selectedOpp") || studio.Account.Name.contains('????')) {
if(component.get("v.selectedCon") || (component.get("v.sFirst") && component.get("v.sLast") && component.get("v.ani"))){
helper.createNewCase(component);
} else {
component.set("v.hasErrors", true);
component.set("v.errors", "Please select a Contact or enter a first name, last name, and phone");
}
} else {
component.set("v.hasErrors", true);
component.set("v.errors", "Please select a studio or opportunity");
}
},
onRadio: function(cmp, evt, helper) {
var selected = evt.getSource().get("v.label");
cmp.set("v.selectedCon", selected);
helper.searchCases(cmp);
},
selectStudio: function(cmp, evt, helper) {
var selected = evt.getSource().get("v.label");
cmp.set("v.selectedStudio", selected);
},
The if statement where you see the bold item is where the logic needs to go. I dont have the right syntax for the item in bold. Any help wuld be appreciated. Thanks
I am 95% done with writing a Lightning Component. What this app does is when a user types in a phone or name, it lists all the contact records associated with the search result. On of the columns is the account name associated with the contact. It also displays a radio button that you need to select. The only thing I have left to do is the following(and I am struggling to get it working):
If the account name starts with a P and a number, so P0232 - Greenwood, then I dont need to select the radio button. Currently, i have an error message popup when its not selected, which should only happen if the name was just Greenwood, for example. Not sure what to put in the conditional to make this work. Here is my code:
Component:
<div style="font-size: 20px">Customer Information</div>
<table>
<tr style="width: 100%;">
<td>
First Name: <lightning:input name="sFirstName" value="{!v.sFirst}"/>
</td>
<td>
Last Name: <lightning:input name="sLastName" value="{!v.sLast}"/>
</td>
<td>
Phone Number: <lightning:input name="sPhone" value="{!v.ani}"/>
</td>
<td style="vertical-align:bottom;">
<lightning:button label="Search" onclick="{!c.doConSearch}" />
</td>
</tr>
</table>
<br />
<aura:if isTrue="{!v.hasContactResults}">
<table>
<thead>
<th>First Name</th>
<th>Last Name</th>
<th>Phone</th>
<th>Mobile</th>
<th>Email</th>
<th>Current Account</th>
<th>City</th>
<th>State</th>
<th>Use This Contact</th>
</thead>
<aura:iteration items="{!v.contacts}" var="con">
<tr>
<td>{!con.FirstName}</td>
<td>{!con.LastName}</td>
<td>{!con.Phone}</td>
<td>{!con.MobilePhone}</td>
<td>{!con.Email}</td>
<td>{!con.Account.Name}</td>
<td>{!con.MailingCity}</td>
<td>{!con.MailingState}</td>
<td><ui:inputRadio name="cons" label="{!con.Id}" labelClass="invis" change="{!c.onRadio}" /></td>
</tr>
</aura:iteration>
</table>
</aura:if>
Here is the Controller:
doConSearch : function(component, event, helper) {
helper.searchContacts(component);
component.set("v.selectedCon", "");
helper.searchCases(component);
if(!component.get("v.showAct")){
var a = component.get('c.getCallQueue');
$A.enqueueAction(a);
}
},
createCase : function(component, event, helper) {
component.set("v.hasErrors", false);
component.set("v.errors", "");
var studio = component.get("v.selectedCon");
if(component.get("v.selectedStudio") || component.get("v.selectedOpp") || studio.Account.Name.contains('????')) {
if(component.get("v.selectedCon") || (component.get("v.sFirst") && component.get("v.sLast") && component.get("v.ani"))){
helper.createNewCase(component);
} else {
component.set("v.hasErrors", true);
component.set("v.errors", "Please select a Contact or enter a first name, last name, and phone");
}
} else {
component.set("v.hasErrors", true);
component.set("v.errors", "Please select a studio or opportunity");
}
},
onRadio: function(cmp, evt, helper) {
var selected = evt.getSource().get("v.label");
cmp.set("v.selectedCon", selected);
helper.searchCases(cmp);
},
selectStudio: function(cmp, evt, helper) {
var selected = evt.getSource().get("v.label");
cmp.set("v.selectedStudio", selected);
},
The if statement where you see the bold item is where the logic needs to go. I dont have the right syntax for the item in bold. Any help wuld be appreciated. Thanks
- Afzaal Hassan
- September 16, 2019
- Like
- 0
How to check if an email contains the right format
I had a simple question. I want to check if an email entered in the form is the right format. How do you splice in apex? In other words I want to see that after the @ symbol, we only have gmail.com. I was going to write something like
if(email__c.contains('@gmail.com'){} but then I realized that this may not be enough because someone could potentially enter an email of gmail.com@hotmail.com for example. So I want to see what I can write in apex to check if the email is in the format ###@gmail.com
Thank you
if(email__c.contains('@gmail.com'){} but then I realized that this may not be enough because someone could potentially enter an email of gmail.com@hotmail.com for example. So I want to see what I can write in apex to check if the email is in the format ###@gmail.com
Thank you
- Afzaal Hassan
- August 28, 2019
- Like
- 0
link address not correct, pdf not opening and throwing error
I created a visualforce page that lists several information in a table format. One component is a pdf attachment. When I am clicking on this attachment, I am getting the following error message (when its redirecting to the url):
Unable to Access Page
The value of the "file" parameter contains a character that is not allowed or the value exceeds the maximum allowed length. Remove the character from the parameter value or reduce the value length and resubmit. If the error still persists, report it to our Customer Support team. Provide the URL of the page you were requesting as well as any other related information.
I clearly am not passing the right URL path but I am not sure what to do. Below is my visualforce code:
<apex:page standardController="Opportunity" extensions="LPP_PDKPrintingController" lightningStylesheets="true">
<apex:form >
<apex:pageBlock title="Shipped" rendered="{!pdkOption=='Shipped'}">
<apex:actionFunction name="searchServer" action="{!runSearch}" rerender="shippedList">
<apex:param name="accountName" value="" />
<apex:param name="LID" value="" />
<apex:param name="JobNo" value="" />
</apex:actionFunction>
<table cellpadding="5" cellspacing="5">
<tr>
<td style="font-weight:bold;">Account Name<br/>
<input style="width:250px" type="text" id="accountName" onkeyup="if(this.value==''){doSearch();}" onkeypress="if(pressedEnter(event)){doSearch();}"/><input type="button" onclick="doSearch();" value="Search"/>
</td>
<td style="font-weight:bold;">LID #<br/>
<input type="text" id="LID" onkeyup="if(this.value==''){doSearch();}" onkeypress="if(pressedEnter(event)){doSearch();}"/><input type="button" onclick="doSearch();" value="Search"/>
</td>
<td style="font-weight:bold;">Job #<br/>
<input type="text" id="JobNo" onkeyup="if(this.value==''){doSearch();}" onkeypress="if(pressedEnter(event)){doSearch();}"/><input type="button" onclick="doSearch();" value="Search"/>
</td>
</tr>
</table>
<apex:outputPanel id="shippedList">
//THIS BELOW LINE IS THE KEY COMPONENT AS IT RELATES TO THE PDF
<apex:pageBlockTable value="{!shippedItems}" var="s">
<apex:column headerValue="PDF">
<apex:outputLink target="_blank" value="{!s.attach}"><apex:image rendered="{!IF(s.attach != null,true,false)}" url="{!$Resource.pdf}" width="25" height="25"/></apex:outputLink>
</apex:column>
<apex:column headerValue="Printed Date">
<apex:outputText value="{!s.printDate}"/>
</apex:column>
</apex:pageBlockTable>
</apex:outputPanel>
</apex:pageBlock>
</apex:outputPanel>
</apex:form>
</apex:page>
The apex controller is below:
public class LPP_PDKPrintingController {
Private ApexPages.StandardController standardController;
Public List<Opportunity> printList {get;set;}
Public List<Opportunity> suppliesList {get;set;}
Public List<shippedItem> shippedItems {get;set;}
Public Integer numToPrint {get;set;}
Public Integer numSupplies {get;set;}
Public Integer numShipped {get;set;}
Public String pdkOption {get;set;}
Public Date dateCompare = system.today()+21;
Public Date dateCompare2 = system.today()+49;
Public Date dateHistory = system.today()-90;
Public Integer batchSize {get;set;}
Public Boolean rushOnly {get;set;}
public LPP_PDKPrintingController (ApexPages.StandardController controller){
//Default batch size
batchSize = 200;
//List of PDKs to be shipped
printList = new List<Opportunity>();
printList = [SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName, Confirmation_Kit_Ship_Status__c
FROM Opportunity WHERE (Confirmation_Kit_Ship_Status__c = '' or Confirmation_Kit_Ship_Status__c = 'Not Shipped' or Confirmation_Kit_Ship_Status__c = 'Reship') and
(Account.LID__c != null and Authorizer__c != null) and
((Year__c = '2017' and (Season__c = 'Summer' or Season__c = 'Fall')) or (Year_Value__c > 2017 and Season__c != null)) and
(stagename='Closed Won' or stagename='Confirmed' or stagename='Scheduled') and ((start_date__c >=TODAY and start_date__c <= :dateCompare)
or (X3_Week_Prior_Call_Complete__c = true and start_date__c <= :dateCompare2))
order by Start_Date__c LIMIT 1000];
numToPrint = printList.size();
//List of Additional Supplies to be shipped
suppliesList = new List<Opportunity>();
suppliesList = [SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName,
Request_Additional_Supplies_Details__c
FROM Opportunity WHERE (Request_Additional_Supplies_Details__c != null) and (Account.LID__c != null and Authorizer__c != null)
and ((Year__c = '2017' and (Season__c = 'Summer' or Season__c = 'Fall')) or (Year_Value__c > 2017 and Season__c != null))
and (stagename='Closed Won' or stagename='Confirmed' or stagename='Scheduled') LIMIT 1000];
numSupplies = suppliesList.size();
//List of PDKs that have been shipped
List<Opportunity> printedList = new List<Opportunity>();
Map<Id, Opportunity> printedMap = new Map<Id, Opportunity>([SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName, PDK_Printed__c
FROM Opportunity WHERE (Confirmation_Kit_Ship_Status__c = 'Shipped' and PDK_Printed__c != null)
and (Account.LID__c != null and Authorizer__c != null) and (stagename='Closed Won' or stagename='Confirmed' or stagename='Scheduled') and start_date__c >=:dateHistory order by PDK_Printed__c Desc LIMIT 1000]);
List<ContentDocumentLink> contentList = new List<ContentDocumentLink>();
contentList = createContentDocumentLinkList(printedMap);
shippedItems = createShippedList(contentList, printedMap);
numShipped = shippedItems.size();
}
// runs the search with parameters passed via Javascript
public PageReference runSearch() {
String accountName = Apexpages.currentPage().getParameters().get('accountName');
String LID = Apexpages.currentPage().getParameters().get('LID');
String JobNo = Apexpages.currentPage().getParameters().get('JobNo');
String query = 'SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName, PDK_Printed__c ';
query += 'FROM Opportunity WHERE (Confirmation_Kit_Ship_Status__c = \'Shipped\' and PDK_Printed__c != null) ';
query += 'and (Account.LID__c != null and Authorizer__c != null) and (stagename=\'Closed Won\' or stagename=\'Confirmed\' or stagename=\'Scheduled\') and start_date__c >=:dateHistory ';
query += 'and LID__c LIKE \'%'+ String.escapeSingleQuotes(LID)+'%\'';
query += 'and Account.Name LIKE \'%'+ String.escapeSingleQuotes(accountName)+'%\'';
query += 'and WPA__c LIKE \'%'+ String.escapeSingleQuotes(JobNo)+'%\'';
List<Opportunity> printedList = new List<Opportunity>();
printedList = Database.query(query);
Map<Id, Opportunity> printedMap = new Map<Id, Opportunity>(printedList);
List<ContentDocumentLink> contentList = new List<ContentDocumentLink>();
contentList = createContentDocumentLinkList(printedMap);
shippedItems = createShippedList(contentList, printedMap);
numShipped = shippedItems.size();
return null;
}
public class shippedItem {
Public String attach {get;set;}
Public String printDate {get;set;}
Public String oppName {get;set;}
Public String accName {get;set;}
Public String lid {get;set;}
Public String job {get;set;}
Public String start {get;set;}
Public String stage {get;set;}
}
Public List<shippedItem> createShippedList(List<ContentDocumentLink> fileList, Map<Id, Opportunity> oppMap)
{
Opportunity o = new Opportunity();
List<shippedItem> shipList = new List<shippedItem>();
for (ContentDocumentLink cdl : fileList) {
o = oppMap.get(cdl.LinkedEntityId);
system.debug(cdl.LinkedEntityId);
if (o != null) {
shippedItem s = new shippedItem();
system.debug(cdl.ContentDocument.Id);
s.attach = '/servlet/servlet.FileDownload?file='+cdl.ContentDocumentId;
system.debug(s.attach);
s.printDate = cdl.ContentDocument.CreatedDate.format();
s.oppName = o.Name;
s.accName = o.Account.Name;
s.lid = o.Account.LID__c;
s.job = o.WPA__c;
if (o.Start_Date__c != null) {
s.start = o.Start_Date__c.format();
}
s.stage = o.StageName;
shipList.add(s);
}
}
return shipList;
}
public List<ContentDocumentLink> createContentDocumentLinkList(Map<Id, Opportunity> printedMap)
{
List<ContentDocumentLink> contentReturnList = new List<ContentDocumentLink>();
Set<Id> printedMapIds = printedMap.keySet();
contentReturnList = [SELECT ContentDocument.Id, ContentDocument.CreatedDate, ContentDocument.Title, LinkedEntityId from ContentDocumentLink where ContentDocument.Title LIKE 'SFP%' and LinkedEntityId IN :printedMapIds order by ContentDocument.CreatedDate Desc LIMIT 1000];
return contentReturnList;
}
/*
* createContentVersion method
* Created by: Brock Irvine
* params: PDKBatchPrintObject, pdfPageBlob
* return: contentReturnList
*/
public ContentVersion createContentVersion (LPP_PDKBatchPrint__c PDKBatchPrintObject, Blob pdfPageBlob)
{
ContentVersion cv = new ContentVersion();
cv.VersionData = pdfPageBlob;
cv.Title = string.valueOf(System.Today()).left(10) + 'BatchPDK.pdf';
cv.ContentLocation = 'S';
cv.PathOnClient = string.valueOf(System.Today()).left(10) + 'BatchPDK.pdf';
cv.FirstPublishLocationId = PDKBatchPrintObject.Id;
insert cv;
return cv;
}
}
I have system debug outputs in there and I am getting the followng values for the system.debug:
USER_DEBUG [145]|DEBUG|0061C00000aYYoaQAG //this is the entityid
18:27:06:642 USER_DEBUG [148]|DEBUG|06923000000GPobAAG //thats the contentdocument.id
USER_DEBUG [151]|DEBUG|/servlet/servlet.FileDownload?file=06923000000GPobAAG //so this is what the url would be
I checked the static respurces and out this id and i see a record which has all the details written and a pdf attachment.
Can someone please let me know what is wrong? Do I have the right id but the wrong path written? Should the path be a different format. Because when I am pasting that exact link in my browser, I also get an error.
Thank you
Unable to Access Page
The value of the "file" parameter contains a character that is not allowed or the value exceeds the maximum allowed length. Remove the character from the parameter value or reduce the value length and resubmit. If the error still persists, report it to our Customer Support team. Provide the URL of the page you were requesting as well as any other related information.
I clearly am not passing the right URL path but I am not sure what to do. Below is my visualforce code:
<apex:page standardController="Opportunity" extensions="LPP_PDKPrintingController" lightningStylesheets="true">
<apex:form >
<apex:pageBlock title="Shipped" rendered="{!pdkOption=='Shipped'}">
<apex:actionFunction name="searchServer" action="{!runSearch}" rerender="shippedList">
<apex:param name="accountName" value="" />
<apex:param name="LID" value="" />
<apex:param name="JobNo" value="" />
</apex:actionFunction>
<table cellpadding="5" cellspacing="5">
<tr>
<td style="font-weight:bold;">Account Name<br/>
<input style="width:250px" type="text" id="accountName" onkeyup="if(this.value==''){doSearch();}" onkeypress="if(pressedEnter(event)){doSearch();}"/><input type="button" onclick="doSearch();" value="Search"/>
</td>
<td style="font-weight:bold;">LID #<br/>
<input type="text" id="LID" onkeyup="if(this.value==''){doSearch();}" onkeypress="if(pressedEnter(event)){doSearch();}"/><input type="button" onclick="doSearch();" value="Search"/>
</td>
<td style="font-weight:bold;">Job #<br/>
<input type="text" id="JobNo" onkeyup="if(this.value==''){doSearch();}" onkeypress="if(pressedEnter(event)){doSearch();}"/><input type="button" onclick="doSearch();" value="Search"/>
</td>
</tr>
</table>
<apex:outputPanel id="shippedList">
//THIS BELOW LINE IS THE KEY COMPONENT AS IT RELATES TO THE PDF
<apex:pageBlockTable value="{!shippedItems}" var="s">
<apex:column headerValue="PDF">
<apex:outputLink target="_blank" value="{!s.attach}"><apex:image rendered="{!IF(s.attach != null,true,false)}" url="{!$Resource.pdf}" width="25" height="25"/></apex:outputLink>
</apex:column>
<apex:column headerValue="Printed Date">
<apex:outputText value="{!s.printDate}"/>
</apex:column>
</apex:pageBlockTable>
</apex:outputPanel>
</apex:pageBlock>
</apex:outputPanel>
</apex:form>
</apex:page>
The apex controller is below:
public class LPP_PDKPrintingController {
Private ApexPages.StandardController standardController;
Public List<Opportunity> printList {get;set;}
Public List<Opportunity> suppliesList {get;set;}
Public List<shippedItem> shippedItems {get;set;}
Public Integer numToPrint {get;set;}
Public Integer numSupplies {get;set;}
Public Integer numShipped {get;set;}
Public String pdkOption {get;set;}
Public Date dateCompare = system.today()+21;
Public Date dateCompare2 = system.today()+49;
Public Date dateHistory = system.today()-90;
Public Integer batchSize {get;set;}
Public Boolean rushOnly {get;set;}
public LPP_PDKPrintingController (ApexPages.StandardController controller){
//Default batch size
batchSize = 200;
//List of PDKs to be shipped
printList = new List<Opportunity>();
printList = [SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName, Confirmation_Kit_Ship_Status__c
FROM Opportunity WHERE (Confirmation_Kit_Ship_Status__c = '' or Confirmation_Kit_Ship_Status__c = 'Not Shipped' or Confirmation_Kit_Ship_Status__c = 'Reship') and
(Account.LID__c != null and Authorizer__c != null) and
((Year__c = '2017' and (Season__c = 'Summer' or Season__c = 'Fall')) or (Year_Value__c > 2017 and Season__c != null)) and
(stagename='Closed Won' or stagename='Confirmed' or stagename='Scheduled') and ((start_date__c >=TODAY and start_date__c <= :dateCompare)
or (X3_Week_Prior_Call_Complete__c = true and start_date__c <= :dateCompare2))
order by Start_Date__c LIMIT 1000];
numToPrint = printList.size();
//List of Additional Supplies to be shipped
suppliesList = new List<Opportunity>();
suppliesList = [SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName,
Request_Additional_Supplies_Details__c
FROM Opportunity WHERE (Request_Additional_Supplies_Details__c != null) and (Account.LID__c != null and Authorizer__c != null)
and ((Year__c = '2017' and (Season__c = 'Summer' or Season__c = 'Fall')) or (Year_Value__c > 2017 and Season__c != null))
and (stagename='Closed Won' or stagename='Confirmed' or stagename='Scheduled') LIMIT 1000];
numSupplies = suppliesList.size();
//List of PDKs that have been shipped
List<Opportunity> printedList = new List<Opportunity>();
Map<Id, Opportunity> printedMap = new Map<Id, Opportunity>([SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName, PDK_Printed__c
FROM Opportunity WHERE (Confirmation_Kit_Ship_Status__c = 'Shipped' and PDK_Printed__c != null)
and (Account.LID__c != null and Authorizer__c != null) and (stagename='Closed Won' or stagename='Confirmed' or stagename='Scheduled') and start_date__c >=:dateHistory order by PDK_Printed__c Desc LIMIT 1000]);
List<ContentDocumentLink> contentList = new List<ContentDocumentLink>();
contentList = createContentDocumentLinkList(printedMap);
shippedItems = createShippedList(contentList, printedMap);
numShipped = shippedItems.size();
}
// runs the search with parameters passed via Javascript
public PageReference runSearch() {
String accountName = Apexpages.currentPage().getParameters().get('accountName');
String LID = Apexpages.currentPage().getParameters().get('LID');
String JobNo = Apexpages.currentPage().getParameters().get('JobNo');
String query = 'SELECT Id, Name, Account.Name, Account.LID__c, Job__c, WPA__c, CloseDate, Start_Date__c, StageName, PDK_Printed__c ';
query += 'FROM Opportunity WHERE (Confirmation_Kit_Ship_Status__c = \'Shipped\' and PDK_Printed__c != null) ';
query += 'and (Account.LID__c != null and Authorizer__c != null) and (stagename=\'Closed Won\' or stagename=\'Confirmed\' or stagename=\'Scheduled\') and start_date__c >=:dateHistory ';
query += 'and LID__c LIKE \'%'+ String.escapeSingleQuotes(LID)+'%\'';
query += 'and Account.Name LIKE \'%'+ String.escapeSingleQuotes(accountName)+'%\'';
query += 'and WPA__c LIKE \'%'+ String.escapeSingleQuotes(JobNo)+'%\'';
List<Opportunity> printedList = new List<Opportunity>();
printedList = Database.query(query);
Map<Id, Opportunity> printedMap = new Map<Id, Opportunity>(printedList);
List<ContentDocumentLink> contentList = new List<ContentDocumentLink>();
contentList = createContentDocumentLinkList(printedMap);
shippedItems = createShippedList(contentList, printedMap);
numShipped = shippedItems.size();
return null;
}
public class shippedItem {
Public String attach {get;set;}
Public String printDate {get;set;}
Public String oppName {get;set;}
Public String accName {get;set;}
Public String lid {get;set;}
Public String job {get;set;}
Public String start {get;set;}
Public String stage {get;set;}
}
Public List<shippedItem> createShippedList(List<ContentDocumentLink> fileList, Map<Id, Opportunity> oppMap)
{
Opportunity o = new Opportunity();
List<shippedItem> shipList = new List<shippedItem>();
for (ContentDocumentLink cdl : fileList) {
o = oppMap.get(cdl.LinkedEntityId);
system.debug(cdl.LinkedEntityId);
if (o != null) {
shippedItem s = new shippedItem();
system.debug(cdl.ContentDocument.Id);
s.attach = '/servlet/servlet.FileDownload?file='+cdl.ContentDocumentId;
system.debug(s.attach);
s.printDate = cdl.ContentDocument.CreatedDate.format();
s.oppName = o.Name;
s.accName = o.Account.Name;
s.lid = o.Account.LID__c;
s.job = o.WPA__c;
if (o.Start_Date__c != null) {
s.start = o.Start_Date__c.format();
}
s.stage = o.StageName;
shipList.add(s);
}
}
return shipList;
}
public List<ContentDocumentLink> createContentDocumentLinkList(Map<Id, Opportunity> printedMap)
{
List<ContentDocumentLink> contentReturnList = new List<ContentDocumentLink>();
Set<Id> printedMapIds = printedMap.keySet();
contentReturnList = [SELECT ContentDocument.Id, ContentDocument.CreatedDate, ContentDocument.Title, LinkedEntityId from ContentDocumentLink where ContentDocument.Title LIKE 'SFP%' and LinkedEntityId IN :printedMapIds order by ContentDocument.CreatedDate Desc LIMIT 1000];
return contentReturnList;
}
/*
* createContentVersion method
* Created by: Brock Irvine
* params: PDKBatchPrintObject, pdfPageBlob
* return: contentReturnList
*/
public ContentVersion createContentVersion (LPP_PDKBatchPrint__c PDKBatchPrintObject, Blob pdfPageBlob)
{
ContentVersion cv = new ContentVersion();
cv.VersionData = pdfPageBlob;
cv.Title = string.valueOf(System.Today()).left(10) + 'BatchPDK.pdf';
cv.ContentLocation = 'S';
cv.PathOnClient = string.valueOf(System.Today()).left(10) + 'BatchPDK.pdf';
cv.FirstPublishLocationId = PDKBatchPrintObject.Id;
insert cv;
return cv;
}
}
I have system debug outputs in there and I am getting the followng values for the system.debug:
USER_DEBUG [145]|DEBUG|0061C00000aYYoaQAG //this is the entityid
18:27:06:642 USER_DEBUG [148]|DEBUG|06923000000GPobAAG //thats the contentdocument.id
USER_DEBUG [151]|DEBUG|/servlet/servlet.FileDownload?file=06923000000GPobAAG //so this is what the url would be
I checked the static respurces and out this id and i see a record which has all the details written and a pdf attachment.
Can someone please let me know what is wrong? Do I have the right id but the wrong path written? Should the path be a different format. Because when I am pasting that exact link in my browser, I also get an error.
Thank you
- Afzaal Hassan
- August 27, 2019
- Like
- 0
Lightning component not iterating list
Hello
I wrote a lightning/aura component. This component lists all the orders associated with a case. When I running a SOQL query, I am getting 5 unique orders for a particular case, for example. But when I am looking at the lightning component, its displaying the same order 5 times. So I am thinking that the aura component is not iterating the apex list properly. I have the code below. Can anyone pinpoint, where I might have gone wrong?
Apex controller:
public class CC_OrderListController {
@AuraEnabled
public static List <Order> getOrders(Id caseId) {
Case c = [select ContactId from Case where Id = :caseId LIMIT 1];
Id con = c.ContactId;
system.debug(con);
List<Order> result = [SELECT Id, BillToContact.Email, EffectiveDate, Sub_Total__c, External_Order_URL__c FROM Order where BillToContactId = :con ORDER BY createdDate DESC LIMIT 20];
system.debug(result);
return (result == null ? new List<Order>() : result);
}
}
Aura component:
<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" controller="CC_OrderListController" access="global">
<aura:attribute name="data" type="Object"/>
<aura:attribute name="columns" type="List"/>
<aura:handler name="init" value="{! this }" action="{! c.init }"/>
<div style="min-height: 200px;">
<lightning:datatable
keyField="id"
data="{! v.data }"
columns="{! v.columns }"
hideCheckboxColumn="true"/>
</div>
</aura:component>
Aura JS controller:
({
init : function(component, event, helper) {
component.set('v.columns', [
{label: 'Email', fieldName: 'Email', type: 'text'},
{label: 'Order Date', fieldName: 'EffectiveDate', type: 'Date'},
{label: 'Sub Total', fieldName: 'Sub_Total__c', type: 'currency'},
{label: 'Order Link', fieldName: 'orderLink', type: 'url'}
]);
var fetchData = {
Email: "",
EffectiveDate : "",
Sub_Total__c : "",
orderLink: ""
};
helper.fetchData(component,fetchData);
}
})
JS Helper method:
({
fetchData : function(component, fetchData) {
var action = component.get('c.getOrders');
action.setParams({ "caseId" : component.get('v.recordId') });
var self = this;
var results = [];
action.setCallback(this, function(actionResult) {
var res = actionResult.getReturnValue();
for(var i = 0; i < res.length;i++){
fetchData.Email = res[i].BillToContact.Email;
fetchData.EffectiveDate = res[i].EffectiveDate;
fetchData.Sub_Total__c = res[i].Sub_Total__c;
fetchData.orderLink = res[i].External_Order_URL__c;
results.push(fetchData);
}
component.set('v.data', results)
});
$A.enqueueAction(action);
}
})
Should I use aura iteration tag ? Any help would be greatly appreciated. Thank you
I wrote a lightning/aura component. This component lists all the orders associated with a case. When I running a SOQL query, I am getting 5 unique orders for a particular case, for example. But when I am looking at the lightning component, its displaying the same order 5 times. So I am thinking that the aura component is not iterating the apex list properly. I have the code below. Can anyone pinpoint, where I might have gone wrong?
Apex controller:
public class CC_OrderListController {
@AuraEnabled
public static List <Order> getOrders(Id caseId) {
Case c = [select ContactId from Case where Id = :caseId LIMIT 1];
Id con = c.ContactId;
system.debug(con);
List<Order> result = [SELECT Id, BillToContact.Email, EffectiveDate, Sub_Total__c, External_Order_URL__c FROM Order where BillToContactId = :con ORDER BY createdDate DESC LIMIT 20];
system.debug(result);
return (result == null ? new List<Order>() : result);
}
}
Aura component:
<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" controller="CC_OrderListController" access="global">
<aura:attribute name="data" type="Object"/>
<aura:attribute name="columns" type="List"/>
<aura:handler name="init" value="{! this }" action="{! c.init }"/>
<div style="min-height: 200px;">
<lightning:datatable
keyField="id"
data="{! v.data }"
columns="{! v.columns }"
hideCheckboxColumn="true"/>
</div>
</aura:component>
Aura JS controller:
({
init : function(component, event, helper) {
component.set('v.columns', [
{label: 'Email', fieldName: 'Email', type: 'text'},
{label: 'Order Date', fieldName: 'EffectiveDate', type: 'Date'},
{label: 'Sub Total', fieldName: 'Sub_Total__c', type: 'currency'},
{label: 'Order Link', fieldName: 'orderLink', type: 'url'}
]);
var fetchData = {
Email: "",
EffectiveDate : "",
Sub_Total__c : "",
orderLink: ""
};
helper.fetchData(component,fetchData);
}
})
JS Helper method:
({
fetchData : function(component, fetchData) {
var action = component.get('c.getOrders');
action.setParams({ "caseId" : component.get('v.recordId') });
var self = this;
var results = [];
action.setCallback(this, function(actionResult) {
var res = actionResult.getReturnValue();
for(var i = 0; i < res.length;i++){
fetchData.Email = res[i].BillToContact.Email;
fetchData.EffectiveDate = res[i].EffectiveDate;
fetchData.Sub_Total__c = res[i].Sub_Total__c;
fetchData.orderLink = res[i].External_Order_URL__c;
results.push(fetchData);
}
component.set('v.data', results)
});
$A.enqueueAction(action);
}
})
Should I use aura iteration tag ? Any help would be greatly appreciated. Thank you
- Afzaal Hassan
- August 16, 2019
- Like
- 0
row lock error on Process Builder
Basically what this PB does is that when the Assigned Resource object changes or gets created, it takes the Photographer name from it and updates the Name in the service appointment object.
There is also this trigger on the service appointment object which creates and updates information on Work order.
I also noticed we have a PB on Opportunity that's updating a field on Service appointment and work order objects and 2 PB on Service Appointment object. So I know that this error is probably happening because multiple processes might be working on the same record.
My question is how do I fix this issue and, most importantly, how do I debug this so that I can isolate which trigger/PB is exactly causing this issue?
I am not very good with Process Builders, and they are causing a lot of errors in my org. If need be I can attach the service appointment trigger and go over what each PB is doing.
There is also this trigger on the service appointment object which creates and updates information on Work order.
I also noticed we have a PB on Opportunity that's updating a field on Service appointment and work order objects and 2 PB on Service Appointment object. So I know that this error is probably happening because multiple processes might be working on the same record.
My question is how do I fix this issue and, most importantly, how do I debug this so that I can isolate which trigger/PB is exactly causing this issue?
I am not very good with Process Builders, and they are causing a lot of errors in my org. If need be I can attach the service appointment trigger and go over what each PB is doing.
- Afzaal Hassan
- July 24, 2019
- Like
- 0
Test class failing for some users but not for others
I have the following test class:
@isTest
public class LPP_ServiceAppointmentTest
{
@TestSetup static void setupData()
{
system.runAs( new User( ID = UserInfo.getUserId() ) )
{
//Create Test Accounts
List<Account> lst_Account = new List<Account> ();
User l_user = LPP_TestUtility.createUser( true );
system.assertNotEquals(null, l_user.Id);
User l_user2 = LPP_TestUtility.createUser(true);
system.assertNotEquals(null, l_user2.Id);
User l_user3 = LPP_TestUtility.createUser(true);
system.assertNotEquals(null, l_user3.id);
system.runAs(l_user){
OperatingHours testOperatingHours = LPP_TestUtility.createOperatingHours('Base Operating hours', 'America/Chicago', true);
system.assertNotEquals(null, testOperatingHours.Id);
//l_loc & l_location
ServiceTerritory testServiceTerritoryAssert = LPP_TestUtility.createServiceTerritory('Test Service Territory', testOperatingHours.Id, true);
system.assertNotEquals(null, testServiceTerritoryAssert.Id);
//parent territory for STM
ServiceTerritory testServiceTerritoryParent = LPP_TestUtility.createServiceTerritory('Test Parent Territory', testOperatingHours.Id, true);
system.assertNotEquals(null, testServiceTerritoryParent.Id);
testServiceTerritoryAssert.ParentTerritoryId = testServiceTerritoryParent.Id;
testServiceTerritoryAssert.User__c = l_user.id;
update testServiceTerritoryAssert;
system.assertEquals(testServiceTerritoryAssert.ParentTerritoryId, testServiceTerritoryParent.Id);
//l_photog
ServiceResource testServiceResource = LPP_TestUtility.createLeadPhotographerFSL('Lead Photographer', l_user.Id, '1234', true);
system.assertNotEquals(null, testServiceResource.Id);
//l_geo_1
Geographic_Assignment__c testGeoAssign1 = LPP_TestUtility.createGeoAssign('MN', 'Hennepin', null, null, l_user.Id, testserviceResource.Id, true);
system.assertNotEquals(null, testGeoAssign1);
//l_acc1
Account l_acc1 = LPP_TestUtility.createAccount('Minnesota' , 'MN', 'Hennepin', 'Minneapolis', '55404', false);
l_acc1.Schools_Verified_Acct__c = true;
insert l_acc1;
System.AssertNotEquals(null,l_acc1.Id);
//Create Test Opportunity
Opportunity l_opp1 = LPP_TestUtility.createOpportunity( l_acc1.id , 'Spring' , string.valueOf(system.today().year()), 'Low Interest' , 'NSS - Opportunity' , 'Group' , 'Classroom Groups' , '2019-2020' , false );
l_opp1.NSS_Won_Reason_Codes__c = 'Referral';
insert l_opp1;
system.assertNotEquals(null, l_opp1);
//l_Photographer1
ServiceResource testServiceResource1 = LPP_TestUtility.createPhotographerFSL('test photographer 1', l_user2.Id, '2345', true);
system.assertNotEquals(null, testServiceResource1.Id);
//l_photographer2
ServiceResource testServiceResource2 = LPP_TestUtility.createPhotographerFSL('test photographer 2', l_user3.id, '3456', true);
system.assertNotEquals(null, testServiceResource2.Id);
//l_PictureType
WorkType testWorkType = LPP_TestUtility.createWorkType('Same Day Proof', 8, true);
system.assertNotEquals(null, testWorkType.Id);
//creating contact
Contact l_cont1 = LPP_TestUtility.createContact(l_acc1.Id, true);
system.assertNotEquals(null, l_cont1.Id);
WorkOrder testWorkOrder = LPP_TestUtility.createWorkOrder(l_acc1.Id, l_opp1.Id, l_cont1.Id, testWorkType.Id, true);
system.assertNotEquals(null, testWorkOrder.Id);
system.assertNotEquals(null, testWorkOrder.WorkTypeId);
//create STM for Assigned Resource
ServiceTerritoryMember testSTM = LPP_TestUtility.createMember(testServiceResource1.Id, testServiceTerritoryAssert.Id, null, false);
testSTM.EffectiveStartDate = system.now().addDays(-10);
insert testSTM;
system.assertNotEquals(null, testSTM.Id);
//create Service Appointments
ServiceAppointment testServiceAppointment1 = LPP_TestUtility.createServiceAppointment(l_opp1.Id, 'Scheduled', testWorkOrder.Id, testServiceTerritoryAssert.Id, system.now()-8, false);
testServiceAppointment1.Photographer__c = testServiceResource1.Id;
insert testServiceAppointment1;
system.assertNotEquals(null, testServiceAppointment1.Id);
//create Assigned Resource for 1st service appointment
AssignedResource testAssignedResource1 = LPP_TestUtility.createAssignedResource(testServiceResource1.Id, testServiceAppointment1.Id, true);
system.assertNotEquals(null, testAssignedResource1.Id);
ServiceAppointment testServiceAppointment2 = LPP_TestUtility.createServiceAppointment(l_opp1.Id, 'Scheduled', testWorkOrder.Id, testServiceTerritoryAssert.Id, system.now()-7, true);
system.assertNotEquals(null, testServiceAppointment2.Id);
//create Assigned Resource for 1st service appointment
AssignedResource testAssignedResource2 = LPP_TestUtility.createAssignedResource(testServiceResource1.Id, testServiceAppointment2.Id, true);
system.assertNotEquals(null, testAssignedResource2.Id);
}
}
}
// This method covers SamePhotographerError method in LPP_ServiceHandler class
@isTest
Static void checksameDayError()
{
system.runAs( new User( ID = UserInfo.getUserId() ) ) {
test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
try
{
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, salist[0].Status, salist[0].ParentRecordId, salist[0].ServiceTerritoryId, salist[0].schedStartTime, false);
saTest.FSL__Related_Service__c = salist[0].Id;
saTest.FSL__Same_Day__c = true;
saTest.Photographer__c = salist[0].Photographer__r.Id;
insert saTest;
}
catch (Exception e)
{
Boolean expectedExceptionThrown = e.getMessage().contains('Photographer cannot be the same when Same Day is selected.') ? true : false;
System.AssertEquals(true, expectedExceptionThrown);
}
test.stopTest();
}
}
// This method covers updateOpptyStage method in LPP_ServiceHandler class
@isTest
static void updateOpptyStage()
{
system.runAs( new User( ID = UserInfo.getUserId() ) )
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
salist[0].Status = 'Dispatched';
update salist[0];
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, salist[0].Status, salist[0].ParentRecordId, salist[0].ServiceTerritoryId, salist[0].schedStartTime, false);
Map<Id, String> saMap = new Map<Id, String>();
saMap.put(saTest.Opportunity__c,'Background Options');
LPP_ServiceAppointmentHandler.updateOpptyStage(saMap);
Test.stopTest();
}
}
// This method covers updateOpptyStage method in LPP_ServiceHandler class
@isTest
static void updateOpptyStartDate()
{
system.runAs( new User( ID = UserInfo.getUserId() ) )
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
salist[0].SchedStartTime = system.now()+10;
salist[0].SchedEndTime = system.now()+11;
update salist[0];
delete salist[0];
undelete salist[0];
Test.stopTest();
}
}
@isTest
static void testClearPictureDayLinking()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
List<ServiceResource> testSR2;
testSR2 = [Select Id from ServiceResource where name = 'test photographer 2'];
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, salist[0].Status, salist[0].ParentRecordId, salist[0].ServiceTerritoryId, salist[0].schedStartTime.addDays(1), false);
saTest.FSL__Related_Service__c = salist[0].Id;
saTest.FSL__Same_Resource__c = true;
saTest.Photographer__c = testSR2[0].Id;
insert saTest;
saTest.Status = 'Canceled';
saTest.FSL__Same_Day__c = true;
update saTest;
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimePA()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(20, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '8:30PM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
} @isTest
static void testResetStartEndTimeAB()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(11, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '11:30AM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimePB()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(22, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '10:30PM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimePC()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(12, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '12:30PM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimeBadData()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(7, 0, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = 'this is a test';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimeNull()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(7, 0, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
}
I live in EST timezone. My other developer lives in CST. When I run this test class, all the methods testResetStartEndTimePA() onwards are failing. Saying the system.assert values are failing because it expected 1130 for example, actual 12:30. They are all 1 hour behind. When my CST timezone friend runs the test class, everything is passing. I am very confused by this. Does anyone have any insight? Thank you
@isTest
public class LPP_ServiceAppointmentTest
{
@TestSetup static void setupData()
{
system.runAs( new User( ID = UserInfo.getUserId() ) )
{
//Create Test Accounts
List<Account> lst_Account = new List<Account> ();
User l_user = LPP_TestUtility.createUser( true );
system.assertNotEquals(null, l_user.Id);
User l_user2 = LPP_TestUtility.createUser(true);
system.assertNotEquals(null, l_user2.Id);
User l_user3 = LPP_TestUtility.createUser(true);
system.assertNotEquals(null, l_user3.id);
system.runAs(l_user){
OperatingHours testOperatingHours = LPP_TestUtility.createOperatingHours('Base Operating hours', 'America/Chicago', true);
system.assertNotEquals(null, testOperatingHours.Id);
//l_loc & l_location
ServiceTerritory testServiceTerritoryAssert = LPP_TestUtility.createServiceTerritory('Test Service Territory', testOperatingHours.Id, true);
system.assertNotEquals(null, testServiceTerritoryAssert.Id);
//parent territory for STM
ServiceTerritory testServiceTerritoryParent = LPP_TestUtility.createServiceTerritory('Test Parent Territory', testOperatingHours.Id, true);
system.assertNotEquals(null, testServiceTerritoryParent.Id);
testServiceTerritoryAssert.ParentTerritoryId = testServiceTerritoryParent.Id;
testServiceTerritoryAssert.User__c = l_user.id;
update testServiceTerritoryAssert;
system.assertEquals(testServiceTerritoryAssert.ParentTerritoryId, testServiceTerritoryParent.Id);
//l_photog
ServiceResource testServiceResource = LPP_TestUtility.createLeadPhotographerFSL('Lead Photographer', l_user.Id, '1234', true);
system.assertNotEquals(null, testServiceResource.Id);
//l_geo_1
Geographic_Assignment__c testGeoAssign1 = LPP_TestUtility.createGeoAssign('MN', 'Hennepin', null, null, l_user.Id, testserviceResource.Id, true);
system.assertNotEquals(null, testGeoAssign1);
//l_acc1
Account l_acc1 = LPP_TestUtility.createAccount('Minnesota' , 'MN', 'Hennepin', 'Minneapolis', '55404', false);
l_acc1.Schools_Verified_Acct__c = true;
insert l_acc1;
System.AssertNotEquals(null,l_acc1.Id);
//Create Test Opportunity
Opportunity l_opp1 = LPP_TestUtility.createOpportunity( l_acc1.id , 'Spring' , string.valueOf(system.today().year()), 'Low Interest' , 'NSS - Opportunity' , 'Group' , 'Classroom Groups' , '2019-2020' , false );
l_opp1.NSS_Won_Reason_Codes__c = 'Referral';
insert l_opp1;
system.assertNotEquals(null, l_opp1);
//l_Photographer1
ServiceResource testServiceResource1 = LPP_TestUtility.createPhotographerFSL('test photographer 1', l_user2.Id, '2345', true);
system.assertNotEquals(null, testServiceResource1.Id);
//l_photographer2
ServiceResource testServiceResource2 = LPP_TestUtility.createPhotographerFSL('test photographer 2', l_user3.id, '3456', true);
system.assertNotEquals(null, testServiceResource2.Id);
//l_PictureType
WorkType testWorkType = LPP_TestUtility.createWorkType('Same Day Proof', 8, true);
system.assertNotEquals(null, testWorkType.Id);
//creating contact
Contact l_cont1 = LPP_TestUtility.createContact(l_acc1.Id, true);
system.assertNotEquals(null, l_cont1.Id);
WorkOrder testWorkOrder = LPP_TestUtility.createWorkOrder(l_acc1.Id, l_opp1.Id, l_cont1.Id, testWorkType.Id, true);
system.assertNotEquals(null, testWorkOrder.Id);
system.assertNotEquals(null, testWorkOrder.WorkTypeId);
//create STM for Assigned Resource
ServiceTerritoryMember testSTM = LPP_TestUtility.createMember(testServiceResource1.Id, testServiceTerritoryAssert.Id, null, false);
testSTM.EffectiveStartDate = system.now().addDays(-10);
insert testSTM;
system.assertNotEquals(null, testSTM.Id);
//create Service Appointments
ServiceAppointment testServiceAppointment1 = LPP_TestUtility.createServiceAppointment(l_opp1.Id, 'Scheduled', testWorkOrder.Id, testServiceTerritoryAssert.Id, system.now()-8, false);
testServiceAppointment1.Photographer__c = testServiceResource1.Id;
insert testServiceAppointment1;
system.assertNotEquals(null, testServiceAppointment1.Id);
//create Assigned Resource for 1st service appointment
AssignedResource testAssignedResource1 = LPP_TestUtility.createAssignedResource(testServiceResource1.Id, testServiceAppointment1.Id, true);
system.assertNotEquals(null, testAssignedResource1.Id);
ServiceAppointment testServiceAppointment2 = LPP_TestUtility.createServiceAppointment(l_opp1.Id, 'Scheduled', testWorkOrder.Id, testServiceTerritoryAssert.Id, system.now()-7, true);
system.assertNotEquals(null, testServiceAppointment2.Id);
//create Assigned Resource for 1st service appointment
AssignedResource testAssignedResource2 = LPP_TestUtility.createAssignedResource(testServiceResource1.Id, testServiceAppointment2.Id, true);
system.assertNotEquals(null, testAssignedResource2.Id);
}
}
}
// This method covers SamePhotographerError method in LPP_ServiceHandler class
@isTest
Static void checksameDayError()
{
system.runAs( new User( ID = UserInfo.getUserId() ) ) {
test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
try
{
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, salist[0].Status, salist[0].ParentRecordId, salist[0].ServiceTerritoryId, salist[0].schedStartTime, false);
saTest.FSL__Related_Service__c = salist[0].Id;
saTest.FSL__Same_Day__c = true;
saTest.Photographer__c = salist[0].Photographer__r.Id;
insert saTest;
}
catch (Exception e)
{
Boolean expectedExceptionThrown = e.getMessage().contains('Photographer cannot be the same when Same Day is selected.') ? true : false;
System.AssertEquals(true, expectedExceptionThrown);
}
test.stopTest();
}
}
// This method covers updateOpptyStage method in LPP_ServiceHandler class
@isTest
static void updateOpptyStage()
{
system.runAs( new User( ID = UserInfo.getUserId() ) )
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
salist[0].Status = 'Dispatched';
update salist[0];
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, salist[0].Status, salist[0].ParentRecordId, salist[0].ServiceTerritoryId, salist[0].schedStartTime, false);
Map<Id, String> saMap = new Map<Id, String>();
saMap.put(saTest.Opportunity__c,'Background Options');
LPP_ServiceAppointmentHandler.updateOpptyStage(saMap);
Test.stopTest();
}
}
// This method covers updateOpptyStage method in LPP_ServiceHandler class
@isTest
static void updateOpptyStartDate()
{
system.runAs( new User( ID = UserInfo.getUserId() ) )
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
salist[0].SchedStartTime = system.now()+10;
salist[0].SchedEndTime = system.now()+11;
update salist[0];
delete salist[0];
undelete salist[0];
Test.stopTest();
}
}
@isTest
static void testClearPictureDayLinking()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
List<ServiceResource> testSR2;
testSR2 = [Select Id from ServiceResource where name = 'test photographer 2'];
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, salist[0].Status, salist[0].ParentRecordId, salist[0].ServiceTerritoryId, salist[0].schedStartTime.addDays(1), false);
saTest.FSL__Related_Service__c = salist[0].Id;
saTest.FSL__Same_Resource__c = true;
saTest.Photographer__c = testSR2[0].Id;
insert saTest;
saTest.Status = 'Canceled';
saTest.FSL__Same_Day__c = true;
update saTest;
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimePA()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(20, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '8:30PM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
} @isTest
static void testResetStartEndTimeAB()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(11, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '11:30AM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimePB()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(22, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '10:30PM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimePC()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(12, 30, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '12:30PM';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimeBadData()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(7, 0, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = 'this is a test';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
@isTest
static void testResetStartEndTimeNull()
{
system.runAs(new User(Id = UserInfo.getUserId()))
{
Test.startTest();
List<ServiceAppointment> salist = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment LIMIT 100];
Time testTime;
//create test service appointment
ServiceAppointment saTest = LPP_TestUtility.createServiceAppointment(salist[0].Opportunity__c, 'Scheduled', salist[0].ParentRecordId, salist[0].serviceTerritoryId, salist[0].schedStartTime, false);
//set testTime to theoretically updated start time when test is over
testTime = Time.newInstance(7, 0, 0, 0);
saTest.Set_Up_Time__c = '7:30AM';
insert saTest;
system.assertNotEquals(null, saTest);
//triggers the code to run because it's in the BeforeUpdate method
saTest.Set_Up_Time__c = '';
update saTest;
//requery and assert
ServiceAppointment saUpdated = [select Id, ParentRecordId, Set_Up_Time__c, Opportunity__c, WorkTypeId, Status, ServiceTerritoryId, schedStartTime, Photographer__r.Id from ServiceAppointment where Id =:saTest.Id];
system.assertEquals(testTime, saUpdated.SchedStartTime.time());
Test.stopTest();
}
}
}
I live in EST timezone. My other developer lives in CST. When I run this test class, all the methods testResetStartEndTimePA() onwards are failing. Saying the system.assert values are failing because it expected 1130 for example, actual 12:30. They are all 1 hour behind. When my CST timezone friend runs the test class, everything is passing. I am very confused by this. Does anyone have any insight? Thank you
- Afzaal Hassan
- June 21, 2019
- Like
- 0
Anonymous Apex class to update object field with User name
Hello
I have an object called Service Territory(ST). The ST has a Name field ad it also has a Lookup field called User (User__c) which looks up to the User object. I just realized for all our ST records, the User__c field is blank. So I decided to run a simple code in anonymous apex window to update these fields. Basically, I want the User__c field to be the value of the User name. So in other words, if the ST name is John Doe, then it will look up to the John Doe User and update User__c with the John Doe record value. This seems simple but for some reason my code is not running. Can somone one please help?
Map<Id, ServiceTerritory> stMap = new Map<Id,ServiceTerritory>([select Id, Name from ServiceTerritory where User__c = null]);
List<User> userList = [select Id, Name from User where Name in :stMap.values()];
Set<ServiceTerritory> srToUpdate = new Set<ServiceTerritory>();
ServiceTerritory sname;
for (User u : userList){
sname = stMap.get(u.Name);
for(st: stMap){
st.User__c = sname
srToUpdate.add(st);
}
}
List<ServiceTerritory> dumbList = new List<Serviceterritory>();
dumbList.addAll(srToUpdate);
update dumbList;
I have an object called Service Territory(ST). The ST has a Name field ad it also has a Lookup field called User (User__c) which looks up to the User object. I just realized for all our ST records, the User__c field is blank. So I decided to run a simple code in anonymous apex window to update these fields. Basically, I want the User__c field to be the value of the User name. So in other words, if the ST name is John Doe, then it will look up to the John Doe User and update User__c with the John Doe record value. This seems simple but for some reason my code is not running. Can somone one please help?
Map<Id, ServiceTerritory> stMap = new Map<Id,ServiceTerritory>([select Id, Name from ServiceTerritory where User__c = null]);
List<User> userList = [select Id, Name from User where Name in :stMap.values()];
Set<ServiceTerritory> srToUpdate = new Set<ServiceTerritory>();
ServiceTerritory sname;
for (User u : userList){
sname = stMap.get(u.Name);
for(st: stMap){
st.User__c = sname
srToUpdate.add(st);
}
}
List<ServiceTerritory> dumbList = new List<Serviceterritory>();
dumbList.addAll(srToUpdate);
update dumbList;
- Afzaal Hassan
- June 19, 2019
- Like
- 0
Convert Process Builder to trigger
I had created a Process Builder which was working fine in the lower sandboxes. In production however, it is causing errors and giving the following message: The flow tried to update these records: null. This error occurred: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY: pi.LogAccountChange: System.LimitException: Apex CPU time limit exceeded. You can look up ExceptionCode values in the SOAP API Developer Guide [developer.salesforce.com] Flow Details Flow API Name: Opportunity_Recalculate_Rating Type: Record Change Process Version: 4 Status: Active Org: Lifetouch (00D15000000kLl0) Flow Interview Details Interview Label: Opportunity_Recalculate_Rating-5_InterviewLabel Current User: Integration User (005150000073iiO) Start time: 3/22/2019 1:57 AM Duration: 15 seconds How the Interview Started Integration User (005150000073iiO) started the flow interview. Some of this flow's variables were set when the interview started. myVariable_old = Opportunity (0061500000WK2cKAAT) myVariable_current = Opportunity (0061500000WK2cKAAT) ASSIGNMENT: myVariable_waitStartTimeAssignment {!myVariable_waitStartTimeVariable} Equals {!$Flow.CurrentDateTime} Result {!myVariable_waitStartTimeVariable} = "3/22/2019 1:57 AM" DECISION: myDecision Executed this outcome: myRule_1 Outcome conditions: {!formula_myRule_1} (true) Equals true RECORD UPDATE: myRule_1_A1 Find all Opportunity records where: Id Equals {!myVariable_current.Id} (0061500000WK2cKAAT) Update the records’ field values. LPP_Rating__c = {!formula_4_myRule_1_A1_9963437625} (B) Result All records that meet the filter criteria are ready to be updated when the next Screen or Wait element is executed or when the interview finishes. RECORD UPDATE: myRule_1_A2 Find all Account records where: Id Equals {!myVariable_current.AccountId} (0011500001LkYu4AAF) Update the records’ field values. Fall_Rating__c = {!formula_3_myRule_1_A2_9151511649} (B) Result All records that meet the filter criteria are ready to be updated when the next Screen or Wait element is executed or when the interview finishes. RECORD UPDATE: myRule_1_A3 Find all Account records where: Id Equals {!myVariable_current.AccountId} (0011500001LkYu4AAF) Update the records’ field values. Spring_Rating__c = {!formula_2_myRule_1_A3_6475583567} (A) Result Failed to update records that meet the filter criteria.
And this error is just a snippet. It actually gives a page long message with the same thing. After doing research, I found out that PB take twice as long to execute as opposed to Apex triggers. So my goal is to convert this Process Builder to an Apex trigger. Unfortunately, I am not a developer and would love to get some guidance/starting step into converting this PB into Apex trigger. The Process Builder is below:
the build formula is: AND ( NOT(ISBLANK([Opportunity].LPP_Rating__c )), TEXT([Opportunity].Collection_Status__c) <> "Open", [Opportunity].Retake__c = false, OR ( ISCHANGED([Opportunity].Total_Payments__c), ISCHANGED([Opportunity].Sales_Tax_Rate__c), ISCHANGED([Opportunity].Reorder_Payments__c), ISCHANGED([Opportunity].Total_Production_Value__c), ISCHANGED([Opportunity].Discount__c), ISCHANGED([Opportunity].Children_Photographed__c), ISCHANGED([Opportunity].Commissions_Paid__c) ) )
The imediate action is:
and the value section has this written:
Basically, what this process is doing is that there is a Rating field that gets updated based on the Contribution Margin formula. However, if any component value in the contribution formula changes, then it updates the rating field. I am guessing this will be a before update trigger. Any help would be greatly appreciated. Thank you
And this error is just a snippet. It actually gives a page long message with the same thing. After doing research, I found out that PB take twice as long to execute as opposed to Apex triggers. So my goal is to convert this Process Builder to an Apex trigger. Unfortunately, I am not a developer and would love to get some guidance/starting step into converting this PB into Apex trigger. The Process Builder is below:
the build formula is: AND ( NOT(ISBLANK([Opportunity].LPP_Rating__c )), TEXT([Opportunity].Collection_Status__c) <> "Open", [Opportunity].Retake__c = false, OR ( ISCHANGED([Opportunity].Total_Payments__c), ISCHANGED([Opportunity].Sales_Tax_Rate__c), ISCHANGED([Opportunity].Reorder_Payments__c), ISCHANGED([Opportunity].Total_Production_Value__c), ISCHANGED([Opportunity].Discount__c), ISCHANGED([Opportunity].Children_Photographed__c), ISCHANGED([Opportunity].Commissions_Paid__c) ) )
The imediate action is:
and the value section has this written:
Basically, what this process is doing is that there is a Rating field that gets updated based on the Contribution Margin formula. However, if any component value in the contribution formula changes, then it updates the rating field. I am guessing this will be a before update trigger. Any help would be greatly appreciated. Thank you
- Afzaal Hassan
- March 26, 2019
- Like
- 0
Apex Test Coverage showing 50% only
Hello
I have written an Apex Batch schedulable class that runs a method from another class everyday at a certain time. What this batch class does is see all the accounts that have a field "Email Sent__c" as true and if it is true, it will pass those clients to the execute function so that it runs a method from a different class. this method basically generates an email and sends it. Once the email is sent, it updates the field Email_Sent__c to false. Everything works great and now in order to deploy it, I am writing some test classes. The problem is that the test class I have written for the Batch Apex only shows 50% coverage. Can someone please let me know why this is only 50% and what I can do to fix it? Also, I dont think the system.assert calls are checking the email_sent values after the update, they are only taking the values from the test setup method
Here is the Batch Apex class I wrote:
global class ConfirmationCardBatchApex implements Database.Batchable<sObject>, Database.Stateful {
global Database.QueryLocator start(Database.BatchableContext BC) {
Datetime clientReleasedDate = Datetime.now().addHours(-24);
return Database.getQueryLocator(
'SELECT Id, Client_Released__c, Client_Number__c, Release_Date__c, ' +
'Email_Sent__c FROM Account ' +
'WHERE Email_Sent__c = true AND Client_Released__c = true AND Release_Date__c<=:clientReleasedDate'
);
}
global void execute( Database.BatchableContext BC, List<Account> scope){
List<String> acctIdList = new List<String>();
for(Account account : scope){
acctIdList.add(account.Id);
}
LM_ChangeAccountRT.resendEmails(acctIdList);
}
global void finish(Database.BatchableContext bc){
System.debug( 'finish: called' );
}
}
The test class I wrote is the following (I am sure it has alot of mistakes. what can i do to get 100% coverage?)
@isTest
public class TestConfirmationCardBatchApex {
static Account client;
static Account client1;
static Account client2;
static Account parentC;
static Contact con;
@testSetup
Contact cont1 = new Contact(LastName='ContTest1', Email='test1contact@libertymutual.com', CommunicationType__c ='Holiday card', recordTypeId = Schema.SObjectType.contact.getRecordTypeInfosByName().get('Business Development Manager').getRecordTypeId(),FirstName= 'Contact');
insert cont1;
id tempuser = [Select id from User where LastName='Testing' limit 1].id;
system.debug('11111'+tempuser);
parentC = TestDataUtils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
parentC.Dealership_Partner__c = 'BMW';
parentC.Dealership_State__c='WA';
parentC.Name = 'Parent Name';
parentC.Client_Number__c = '12302.0';
parentC.Business_Development_Manager__c=cont1.id;
insert parentC;
client1 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client1.Name = 'Test Client 2';
client1.Business_Development_Manager__c=cont1.id;
client1.Branch_Manager__c = tempuser;
client1.Dealership_Partner__c = 'BMW';
client1.Dealership_State__c= 'TX';
client1.ParentID = parentC.Id;
client1.Client_Number__c = '12322.0';
client1.Email_Sent__c = true;
client1.Client_Released__c = true;
accountdata.add(client1);
client2 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client2.Name = 'Test Client 3';
client2.Business_Development_Manager__c=cont1.id;
client2.Branch_Manager__c = tempuser;
client2.Dealership_Partner__c = 'BMW';
client2.Dealership_State__c= 'CA';
client2.ParentID = parentC.Id;
client2.Client_Number__c = '12332.0';
client2.Email_Sent__c = true;
client2.Client_Released__c = true;
accountdata.add(client2);
insert accountdata;
static testmethod void test() {
Test.startTest();
ConfirmationCardBatchApex confirm = new ConfirmationCardBatchApex();
Id batchId = Database.executeBatch(confirm);
Account emailTest = [SELECT Id, Name, Client_Released__c, Client_Number__c, Release_Date__c, Email_Sent__c FROM Account WHERE Name IN ('ContTest1', 'Test Client 1', 'Test Client 2') AND Email_Sent__c = true];
Test.stopTest();
System.assertEquals(true, emailTest.Email_Sent__c, 'Expected value should be true'); // After method is run, the email_sent__c should be false but it only shows success when I assert it to true.
}
}
In case you are wondering what this resendemails method is(in the LM_CHANGEACCOUNTRT Class), here is a snippet of it:
@AuraEnabled
public static String resendEmails(List<String> accountIdList) {
String response = null;
try {
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() ||
sysAdmin.Id == userinfo.getProfileId()) {
List<Account> accList = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,Existing_Participant__c,
Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,Client_Number__c,Closing_Manager__r.name,
Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,Is_a_broker_receiving_compensation__c,Broker__r.name,
,Broker__r.State__c, Email_Sent__c,
FROM Account
WHERE Id IN:accountIdList];
for(Account acc: accList){
if (acc.Client_Number__c != null && acc.Client_Released__c && acc.Email_Sent__c == true) {
sendpdfgenerationEmails(acc);
acc.Email_Sent__c = false;
response = 'Email Sent';
}else {
response= 'Access Denied';
}
}
update accList;
}
}catch(Exception e) {
System.debug(e.getMessage());
response = 'Error sending emails';
}
return response;
}//what this method does is call the sendpdfgeneration method which is the method that generates and sends a custom email. After calling the methid, the email_sent__c field is updated to false
Any help in fixing my test method would be great;y appreciated. Thank you
I have written an Apex Batch schedulable class that runs a method from another class everyday at a certain time. What this batch class does is see all the accounts that have a field "Email Sent__c" as true and if it is true, it will pass those clients to the execute function so that it runs a method from a different class. this method basically generates an email and sends it. Once the email is sent, it updates the field Email_Sent__c to false. Everything works great and now in order to deploy it, I am writing some test classes. The problem is that the test class I have written for the Batch Apex only shows 50% coverage. Can someone please let me know why this is only 50% and what I can do to fix it? Also, I dont think the system.assert calls are checking the email_sent values after the update, they are only taking the values from the test setup method
Here is the Batch Apex class I wrote:
global class ConfirmationCardBatchApex implements Database.Batchable<sObject>, Database.Stateful {
global Database.QueryLocator start(Database.BatchableContext BC) {
Datetime clientReleasedDate = Datetime.now().addHours(-24);
return Database.getQueryLocator(
'SELECT Id, Client_Released__c, Client_Number__c, Release_Date__c, ' +
'Email_Sent__c FROM Account ' +
'WHERE Email_Sent__c = true AND Client_Released__c = true AND Release_Date__c<=:clientReleasedDate'
);
}
global void execute( Database.BatchableContext BC, List<Account> scope){
List<String> acctIdList = new List<String>();
for(Account account : scope){
acctIdList.add(account.Id);
}
LM_ChangeAccountRT.resendEmails(acctIdList);
}
global void finish(Database.BatchableContext bc){
System.debug( 'finish: called' );
}
}
The test class I wrote is the following (I am sure it has alot of mistakes. what can i do to get 100% coverage?)
@isTest
public class TestConfirmationCardBatchApex {
static Account client;
static Account client1;
static Account client2;
static Account parentC;
static Contact con;
@testSetup
Contact cont1 = new Contact(LastName='ContTest1', Email='test1contact@libertymutual.com', CommunicationType__c ='Holiday card', recordTypeId = Schema.SObjectType.contact.getRecordTypeInfosByName().get('Business Development Manager').getRecordTypeId(),FirstName= 'Contact');
insert cont1;
id tempuser = [Select id from User where LastName='Testing' limit 1].id;
system.debug('11111'+tempuser);
parentC = TestDataUtils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
parentC.Dealership_Partner__c = 'BMW';
parentC.Dealership_State__c='WA';
parentC.Name = 'Parent Name';
parentC.Client_Number__c = '12302.0';
parentC.Business_Development_Manager__c=cont1.id;
insert parentC;
client1 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client1.Name = 'Test Client 2';
client1.Business_Development_Manager__c=cont1.id;
client1.Branch_Manager__c = tempuser;
client1.Dealership_Partner__c = 'BMW';
client1.Dealership_State__c= 'TX';
client1.ParentID = parentC.Id;
client1.Client_Number__c = '12322.0';
client1.Email_Sent__c = true;
client1.Client_Released__c = true;
accountdata.add(client1);
client2 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client2.Name = 'Test Client 3';
client2.Business_Development_Manager__c=cont1.id;
client2.Branch_Manager__c = tempuser;
client2.Dealership_Partner__c = 'BMW';
client2.Dealership_State__c= 'CA';
client2.ParentID = parentC.Id;
client2.Client_Number__c = '12332.0';
client2.Email_Sent__c = true;
client2.Client_Released__c = true;
accountdata.add(client2);
insert accountdata;
static testmethod void test() {
Test.startTest();
ConfirmationCardBatchApex confirm = new ConfirmationCardBatchApex();
Id batchId = Database.executeBatch(confirm);
Account emailTest = [SELECT Id, Name, Client_Released__c, Client_Number__c, Release_Date__c, Email_Sent__c FROM Account WHERE Name IN ('ContTest1', 'Test Client 1', 'Test Client 2') AND Email_Sent__c = true];
Test.stopTest();
System.assertEquals(true, emailTest.Email_Sent__c, 'Expected value should be true'); // After method is run, the email_sent__c should be false but it only shows success when I assert it to true.
}
}
In case you are wondering what this resendemails method is(in the LM_CHANGEACCOUNTRT Class), here is a snippet of it:
@AuraEnabled
public static String resendEmails(List<String> accountIdList) {
String response = null;
try {
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() ||
sysAdmin.Id == userinfo.getProfileId()) {
List<Account> accList = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,Existing_Participant__c,
Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,Client_Number__c,Closing_Manager__r.name,
Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,Is_a_broker_receiving_compensation__c,Broker__r.name,
,Broker__r.State__c, Email_Sent__c,
FROM Account
WHERE Id IN:accountIdList];
for(Account acc: accList){
if (acc.Client_Number__c != null && acc.Client_Released__c && acc.Email_Sent__c == true) {
sendpdfgenerationEmails(acc);
acc.Email_Sent__c = false;
response = 'Email Sent';
}else {
response= 'Access Denied';
}
}
update accList;
}
}catch(Exception e) {
System.debug(e.getMessage());
response = 'Error sending emails';
}
return response;
}//what this method does is call the sendpdfgeneration method which is the method that generates and sends a custom email. After calling the methid, the email_sent__c field is updated to false
Any help in fixing my test method would be great;y appreciated. Thank you
- Afzaal Hassan
- November 27, 2018
- Like
- 0
Database query syntax error
Hello
I have written a scheduled apex batch job which compiles fine. However, when I ran the job, the queue (in the UI) says the following error:
"First error: value of filter criterion for field 'Client_Released_Date__c' must be of type dateTime and should not be enclosed in quotes". Below is my start method for the scheduled batch apex:
global Database.QueryLocator start(Database.BatchableContext BC) {
Datetime clientReleasedDate = Datetime.now().addHours(-1);
return Database.getQueryLocator(
'SELECT Id, Client_Released__c, Client_Number__c, Client_Release_Date__c, ' +
'Email_Sent__c FROM Account ' +
'WHERE Email_Sent__c = true AND Client_Released__c = true AND Client_Release_Date__c>= \''+ clientReleasedDate +'\''
);
}
I check the client_released_date__c and I confirmed that it is a datetime field. So the datatype matches. I am suspecting I have my SOQL query syntax wrong. Perhaps I am escaping the quotes when I dont need to. Can someone please check and correct my method/syntax for the query locator?
Thanks
I have written a scheduled apex batch job which compiles fine. However, when I ran the job, the queue (in the UI) says the following error:
"First error: value of filter criterion for field 'Client_Released_Date__c' must be of type dateTime and should not be enclosed in quotes". Below is my start method for the scheduled batch apex:
global Database.QueryLocator start(Database.BatchableContext BC) {
Datetime clientReleasedDate = Datetime.now().addHours(-1);
return Database.getQueryLocator(
'SELECT Id, Client_Released__c, Client_Number__c, Client_Release_Date__c, ' +
'Email_Sent__c FROM Account ' +
'WHERE Email_Sent__c = true AND Client_Released__c = true AND Client_Release_Date__c>= \''+ clientReleasedDate +'\''
);
}
I check the client_released_date__c and I confirmed that it is a datetime field. So the datatype matches. I am suspecting I have my SOQL query syntax wrong. Perhaps I am escaping the quotes when I dont need to. Can someone please check and correct my method/syntax for the query locator?
Thanks
- Afzaal Hassan
- November 14, 2018
- Like
- 0
Render a Javascript generated barcode as pdf
I am using a JS library called barcode39 to create a barcode image. I already imported the JS library in the static resource and have included the JS in my visualforce page. The barcode is generating fine in the VF page. The problem is I need to render this page as a pdf. When I do that, the barcode image does not appear. I DO NOT want to use the image url from barcodeinc because its very unstable. Can you please let me know what I can do to modify the code below to make the barcode render in pdf as well? Thank you
<apex:page standardController="Opportunity" extensions="LPP_PackingSlip" showHeader="false" sidebar="false" renderAs="pdf" standardStylesheets="false" applyHtmlTag="false">
<apex:includeScript value="{!$Resource.BarcodeScript}"/>
<head>
<body>
<apex:outputText rendered="{!hasPictureDays}">
<!--Header-->
<br/>
<div class="headerSlip">{!Opportunity.Account.Name}</div><br/>
<div class="jobSlip">{!Opportunity.WPA__c}</div>
<center><svg id="barcode"></svg></center>
<br/><br/>
</apex:outputText>
</body>
<script type ="text/javascript">
JsBarcode("#barcode", "{!Opportunity.WPA__c}",{
fontOptions: "both",
font : "OCRB",
textAlign : "center",
Textmargin : 5,
fontSize : 12,
width: 1,
height: 50
});
</script>
</apex:page>
<apex:page standardController="Opportunity" extensions="LPP_PackingSlip" showHeader="false" sidebar="false" renderAs="pdf" standardStylesheets="false" applyHtmlTag="false">
<apex:includeScript value="{!$Resource.BarcodeScript}"/>
<head>
<body>
<apex:outputText rendered="{!hasPictureDays}">
<!--Header-->
<br/>
<div class="headerSlip">{!Opportunity.Account.Name}</div><br/>
<div class="jobSlip">{!Opportunity.WPA__c}</div>
<center><svg id="barcode"></svg></center>
<br/><br/>
</apex:outputText>
</body>
<script type ="text/javascript">
JsBarcode("#barcode", "{!Opportunity.WPA__c}",{
fontOptions: "both",
font : "OCRB",
textAlign : "center",
Textmargin : 5,
fontSize : 12,
width: 1,
height: 50
});
</script>
</apex:page>
- Afzaal Hassan
- October 31, 2019
- Like
- 0
How to check if an email contains the right format
I had a simple question. I want to check if an email entered in the form is the right format. How do you splice in apex? In other words I want to see that after the @ symbol, we only have gmail.com. I was going to write something like
if(email__c.contains('@gmail.com'){} but then I realized that this may not be enough because someone could potentially enter an email of gmail.com@hotmail.com for example. So I want to see what I can write in apex to check if the email is in the format ###@gmail.com
Thank you
if(email__c.contains('@gmail.com'){} but then I realized that this may not be enough because someone could potentially enter an email of gmail.com@hotmail.com for example. So I want to see what I can write in apex to check if the email is in the format ###@gmail.com
Thank you
- Afzaal Hassan
- August 28, 2019
- Like
- 0
Lightning component not iterating list
Hello
I wrote a lightning/aura component. This component lists all the orders associated with a case. When I running a SOQL query, I am getting 5 unique orders for a particular case, for example. But when I am looking at the lightning component, its displaying the same order 5 times. So I am thinking that the aura component is not iterating the apex list properly. I have the code below. Can anyone pinpoint, where I might have gone wrong?
Apex controller:
public class CC_OrderListController {
@AuraEnabled
public static List <Order> getOrders(Id caseId) {
Case c = [select ContactId from Case where Id = :caseId LIMIT 1];
Id con = c.ContactId;
system.debug(con);
List<Order> result = [SELECT Id, BillToContact.Email, EffectiveDate, Sub_Total__c, External_Order_URL__c FROM Order where BillToContactId = :con ORDER BY createdDate DESC LIMIT 20];
system.debug(result);
return (result == null ? new List<Order>() : result);
}
}
Aura component:
<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" controller="CC_OrderListController" access="global">
<aura:attribute name="data" type="Object"/>
<aura:attribute name="columns" type="List"/>
<aura:handler name="init" value="{! this }" action="{! c.init }"/>
<div style="min-height: 200px;">
<lightning:datatable
keyField="id"
data="{! v.data }"
columns="{! v.columns }"
hideCheckboxColumn="true"/>
</div>
</aura:component>
Aura JS controller:
({
init : function(component, event, helper) {
component.set('v.columns', [
{label: 'Email', fieldName: 'Email', type: 'text'},
{label: 'Order Date', fieldName: 'EffectiveDate', type: 'Date'},
{label: 'Sub Total', fieldName: 'Sub_Total__c', type: 'currency'},
{label: 'Order Link', fieldName: 'orderLink', type: 'url'}
]);
var fetchData = {
Email: "",
EffectiveDate : "",
Sub_Total__c : "",
orderLink: ""
};
helper.fetchData(component,fetchData);
}
})
JS Helper method:
({
fetchData : function(component, fetchData) {
var action = component.get('c.getOrders');
action.setParams({ "caseId" : component.get('v.recordId') });
var self = this;
var results = [];
action.setCallback(this, function(actionResult) {
var res = actionResult.getReturnValue();
for(var i = 0; i < res.length;i++){
fetchData.Email = res[i].BillToContact.Email;
fetchData.EffectiveDate = res[i].EffectiveDate;
fetchData.Sub_Total__c = res[i].Sub_Total__c;
fetchData.orderLink = res[i].External_Order_URL__c;
results.push(fetchData);
}
component.set('v.data', results)
});
$A.enqueueAction(action);
}
})
Should I use aura iteration tag ? Any help would be greatly appreciated. Thank you
I wrote a lightning/aura component. This component lists all the orders associated with a case. When I running a SOQL query, I am getting 5 unique orders for a particular case, for example. But when I am looking at the lightning component, its displaying the same order 5 times. So I am thinking that the aura component is not iterating the apex list properly. I have the code below. Can anyone pinpoint, where I might have gone wrong?
Apex controller:
public class CC_OrderListController {
@AuraEnabled
public static List <Order> getOrders(Id caseId) {
Case c = [select ContactId from Case where Id = :caseId LIMIT 1];
Id con = c.ContactId;
system.debug(con);
List<Order> result = [SELECT Id, BillToContact.Email, EffectiveDate, Sub_Total__c, External_Order_URL__c FROM Order where BillToContactId = :con ORDER BY createdDate DESC LIMIT 20];
system.debug(result);
return (result == null ? new List<Order>() : result);
}
}
Aura component:
<aura:component implements="flexipage:availableForAllPageTypes,force:hasRecordId" controller="CC_OrderListController" access="global">
<aura:attribute name="data" type="Object"/>
<aura:attribute name="columns" type="List"/>
<aura:handler name="init" value="{! this }" action="{! c.init }"/>
<div style="min-height: 200px;">
<lightning:datatable
keyField="id"
data="{! v.data }"
columns="{! v.columns }"
hideCheckboxColumn="true"/>
</div>
</aura:component>
Aura JS controller:
({
init : function(component, event, helper) {
component.set('v.columns', [
{label: 'Email', fieldName: 'Email', type: 'text'},
{label: 'Order Date', fieldName: 'EffectiveDate', type: 'Date'},
{label: 'Sub Total', fieldName: 'Sub_Total__c', type: 'currency'},
{label: 'Order Link', fieldName: 'orderLink', type: 'url'}
]);
var fetchData = {
Email: "",
EffectiveDate : "",
Sub_Total__c : "",
orderLink: ""
};
helper.fetchData(component,fetchData);
}
})
JS Helper method:
({
fetchData : function(component, fetchData) {
var action = component.get('c.getOrders');
action.setParams({ "caseId" : component.get('v.recordId') });
var self = this;
var results = [];
action.setCallback(this, function(actionResult) {
var res = actionResult.getReturnValue();
for(var i = 0; i < res.length;i++){
fetchData.Email = res[i].BillToContact.Email;
fetchData.EffectiveDate = res[i].EffectiveDate;
fetchData.Sub_Total__c = res[i].Sub_Total__c;
fetchData.orderLink = res[i].External_Order_URL__c;
results.push(fetchData);
}
component.set('v.data', results)
});
$A.enqueueAction(action);
}
})
Should I use aura iteration tag ? Any help would be greatly appreciated. Thank you
- Afzaal Hassan
- August 16, 2019
- Like
- 0
Anonymous Apex class to update object field with User name
Hello
I have an object called Service Territory(ST). The ST has a Name field ad it also has a Lookup field called User (User__c) which looks up to the User object. I just realized for all our ST records, the User__c field is blank. So I decided to run a simple code in anonymous apex window to update these fields. Basically, I want the User__c field to be the value of the User name. So in other words, if the ST name is John Doe, then it will look up to the John Doe User and update User__c with the John Doe record value. This seems simple but for some reason my code is not running. Can somone one please help?
Map<Id, ServiceTerritory> stMap = new Map<Id,ServiceTerritory>([select Id, Name from ServiceTerritory where User__c = null]);
List<User> userList = [select Id, Name from User where Name in :stMap.values()];
Set<ServiceTerritory> srToUpdate = new Set<ServiceTerritory>();
ServiceTerritory sname;
for (User u : userList){
sname = stMap.get(u.Name);
for(st: stMap){
st.User__c = sname
srToUpdate.add(st);
}
}
List<ServiceTerritory> dumbList = new List<Serviceterritory>();
dumbList.addAll(srToUpdate);
update dumbList;
I have an object called Service Territory(ST). The ST has a Name field ad it also has a Lookup field called User (User__c) which looks up to the User object. I just realized for all our ST records, the User__c field is blank. So I decided to run a simple code in anonymous apex window to update these fields. Basically, I want the User__c field to be the value of the User name. So in other words, if the ST name is John Doe, then it will look up to the John Doe User and update User__c with the John Doe record value. This seems simple but for some reason my code is not running. Can somone one please help?
Map<Id, ServiceTerritory> stMap = new Map<Id,ServiceTerritory>([select Id, Name from ServiceTerritory where User__c = null]);
List<User> userList = [select Id, Name from User where Name in :stMap.values()];
Set<ServiceTerritory> srToUpdate = new Set<ServiceTerritory>();
ServiceTerritory sname;
for (User u : userList){
sname = stMap.get(u.Name);
for(st: stMap){
st.User__c = sname
srToUpdate.add(st);
}
}
List<ServiceTerritory> dumbList = new List<Serviceterritory>();
dumbList.addAll(srToUpdate);
update dumbList;
- Afzaal Hassan
- June 19, 2019
- Like
- 0
Convert Process Builder to trigger
I had created a Process Builder which was working fine in the lower sandboxes. In production however, it is causing errors and giving the following message: The flow tried to update these records: null. This error occurred: CANNOT_INSERT_UPDATE_ACTIVATE_ENTITY: pi.LogAccountChange: System.LimitException: Apex CPU time limit exceeded. You can look up ExceptionCode values in the SOAP API Developer Guide [developer.salesforce.com] Flow Details Flow API Name: Opportunity_Recalculate_Rating Type: Record Change Process Version: 4 Status: Active Org: Lifetouch (00D15000000kLl0) Flow Interview Details Interview Label: Opportunity_Recalculate_Rating-5_InterviewLabel Current User: Integration User (005150000073iiO) Start time: 3/22/2019 1:57 AM Duration: 15 seconds How the Interview Started Integration User (005150000073iiO) started the flow interview. Some of this flow's variables were set when the interview started. myVariable_old = Opportunity (0061500000WK2cKAAT) myVariable_current = Opportunity (0061500000WK2cKAAT) ASSIGNMENT: myVariable_waitStartTimeAssignment {!myVariable_waitStartTimeVariable} Equals {!$Flow.CurrentDateTime} Result {!myVariable_waitStartTimeVariable} = "3/22/2019 1:57 AM" DECISION: myDecision Executed this outcome: myRule_1 Outcome conditions: {!formula_myRule_1} (true) Equals true RECORD UPDATE: myRule_1_A1 Find all Opportunity records where: Id Equals {!myVariable_current.Id} (0061500000WK2cKAAT) Update the records’ field values. LPP_Rating__c = {!formula_4_myRule_1_A1_9963437625} (B) Result All records that meet the filter criteria are ready to be updated when the next Screen or Wait element is executed or when the interview finishes. RECORD UPDATE: myRule_1_A2 Find all Account records where: Id Equals {!myVariable_current.AccountId} (0011500001LkYu4AAF) Update the records’ field values. Fall_Rating__c = {!formula_3_myRule_1_A2_9151511649} (B) Result All records that meet the filter criteria are ready to be updated when the next Screen or Wait element is executed or when the interview finishes. RECORD UPDATE: myRule_1_A3 Find all Account records where: Id Equals {!myVariable_current.AccountId} (0011500001LkYu4AAF) Update the records’ field values. Spring_Rating__c = {!formula_2_myRule_1_A3_6475583567} (A) Result Failed to update records that meet the filter criteria.
And this error is just a snippet. It actually gives a page long message with the same thing. After doing research, I found out that PB take twice as long to execute as opposed to Apex triggers. So my goal is to convert this Process Builder to an Apex trigger. Unfortunately, I am not a developer and would love to get some guidance/starting step into converting this PB into Apex trigger. The Process Builder is below:
the build formula is: AND ( NOT(ISBLANK([Opportunity].LPP_Rating__c )), TEXT([Opportunity].Collection_Status__c) <> "Open", [Opportunity].Retake__c = false, OR ( ISCHANGED([Opportunity].Total_Payments__c), ISCHANGED([Opportunity].Sales_Tax_Rate__c), ISCHANGED([Opportunity].Reorder_Payments__c), ISCHANGED([Opportunity].Total_Production_Value__c), ISCHANGED([Opportunity].Discount__c), ISCHANGED([Opportunity].Children_Photographed__c), ISCHANGED([Opportunity].Commissions_Paid__c) ) )
The imediate action is:
and the value section has this written:
Basically, what this process is doing is that there is a Rating field that gets updated based on the Contribution Margin formula. However, if any component value in the contribution formula changes, then it updates the rating field. I am guessing this will be a before update trigger. Any help would be greatly appreciated. Thank you
And this error is just a snippet. It actually gives a page long message with the same thing. After doing research, I found out that PB take twice as long to execute as opposed to Apex triggers. So my goal is to convert this Process Builder to an Apex trigger. Unfortunately, I am not a developer and would love to get some guidance/starting step into converting this PB into Apex trigger. The Process Builder is below:
the build formula is: AND ( NOT(ISBLANK([Opportunity].LPP_Rating__c )), TEXT([Opportunity].Collection_Status__c) <> "Open", [Opportunity].Retake__c = false, OR ( ISCHANGED([Opportunity].Total_Payments__c), ISCHANGED([Opportunity].Sales_Tax_Rate__c), ISCHANGED([Opportunity].Reorder_Payments__c), ISCHANGED([Opportunity].Total_Production_Value__c), ISCHANGED([Opportunity].Discount__c), ISCHANGED([Opportunity].Children_Photographed__c), ISCHANGED([Opportunity].Commissions_Paid__c) ) )
The imediate action is:
and the value section has this written:
Basically, what this process is doing is that there is a Rating field that gets updated based on the Contribution Margin formula. However, if any component value in the contribution formula changes, then it updates the rating field. I am guessing this will be a before update trigger. Any help would be greatly appreciated. Thank you
- Afzaal Hassan
- March 26, 2019
- Like
- 0
Apex Test Coverage showing 50% only
Hello
I have written an Apex Batch schedulable class that runs a method from another class everyday at a certain time. What this batch class does is see all the accounts that have a field "Email Sent__c" as true and if it is true, it will pass those clients to the execute function so that it runs a method from a different class. this method basically generates an email and sends it. Once the email is sent, it updates the field Email_Sent__c to false. Everything works great and now in order to deploy it, I am writing some test classes. The problem is that the test class I have written for the Batch Apex only shows 50% coverage. Can someone please let me know why this is only 50% and what I can do to fix it? Also, I dont think the system.assert calls are checking the email_sent values after the update, they are only taking the values from the test setup method
Here is the Batch Apex class I wrote:
global class ConfirmationCardBatchApex implements Database.Batchable<sObject>, Database.Stateful {
global Database.QueryLocator start(Database.BatchableContext BC) {
Datetime clientReleasedDate = Datetime.now().addHours(-24);
return Database.getQueryLocator(
'SELECT Id, Client_Released__c, Client_Number__c, Release_Date__c, ' +
'Email_Sent__c FROM Account ' +
'WHERE Email_Sent__c = true AND Client_Released__c = true AND Release_Date__c<=:clientReleasedDate'
);
}
global void execute( Database.BatchableContext BC, List<Account> scope){
List<String> acctIdList = new List<String>();
for(Account account : scope){
acctIdList.add(account.Id);
}
LM_ChangeAccountRT.resendEmails(acctIdList);
}
global void finish(Database.BatchableContext bc){
System.debug( 'finish: called' );
}
}
The test class I wrote is the following (I am sure it has alot of mistakes. what can i do to get 100% coverage?)
@isTest
public class TestConfirmationCardBatchApex {
static Account client;
static Account client1;
static Account client2;
static Account parentC;
static Contact con;
@testSetup
Contact cont1 = new Contact(LastName='ContTest1', Email='test1contact@libertymutual.com', CommunicationType__c ='Holiday card', recordTypeId = Schema.SObjectType.contact.getRecordTypeInfosByName().get('Business Development Manager').getRecordTypeId(),FirstName= 'Contact');
insert cont1;
id tempuser = [Select id from User where LastName='Testing' limit 1].id;
system.debug('11111'+tempuser);
parentC = TestDataUtils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
parentC.Dealership_Partner__c = 'BMW';
parentC.Dealership_State__c='WA';
parentC.Name = 'Parent Name';
parentC.Client_Number__c = '12302.0';
parentC.Business_Development_Manager__c=cont1.id;
insert parentC;
client1 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client1.Name = 'Test Client 2';
client1.Business_Development_Manager__c=cont1.id;
client1.Branch_Manager__c = tempuser;
client1.Dealership_Partner__c = 'BMW';
client1.Dealership_State__c= 'TX';
client1.ParentID = parentC.Id;
client1.Client_Number__c = '12322.0';
client1.Email_Sent__c = true;
client1.Client_Released__c = true;
accountdata.add(client1);
client2 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client2.Name = 'Test Client 3';
client2.Business_Development_Manager__c=cont1.id;
client2.Branch_Manager__c = tempuser;
client2.Dealership_Partner__c = 'BMW';
client2.Dealership_State__c= 'CA';
client2.ParentID = parentC.Id;
client2.Client_Number__c = '12332.0';
client2.Email_Sent__c = true;
client2.Client_Released__c = true;
accountdata.add(client2);
insert accountdata;
static testmethod void test() {
Test.startTest();
ConfirmationCardBatchApex confirm = new ConfirmationCardBatchApex();
Id batchId = Database.executeBatch(confirm);
Account emailTest = [SELECT Id, Name, Client_Released__c, Client_Number__c, Release_Date__c, Email_Sent__c FROM Account WHERE Name IN ('ContTest1', 'Test Client 1', 'Test Client 2') AND Email_Sent__c = true];
Test.stopTest();
System.assertEquals(true, emailTest.Email_Sent__c, 'Expected value should be true'); // After method is run, the email_sent__c should be false but it only shows success when I assert it to true.
}
}
In case you are wondering what this resendemails method is(in the LM_CHANGEACCOUNTRT Class), here is a snippet of it:
@AuraEnabled
public static String resendEmails(List<String> accountIdList) {
String response = null;
try {
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() ||
sysAdmin.Id == userinfo.getProfileId()) {
List<Account> accList = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,Existing_Participant__c,
Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,Client_Number__c,Closing_Manager__r.name,
Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,Is_a_broker_receiving_compensation__c,Broker__r.name,
,Broker__r.State__c, Email_Sent__c,
FROM Account
WHERE Id IN:accountIdList];
for(Account acc: accList){
if (acc.Client_Number__c != null && acc.Client_Released__c && acc.Email_Sent__c == true) {
sendpdfgenerationEmails(acc);
acc.Email_Sent__c = false;
response = 'Email Sent';
}else {
response= 'Access Denied';
}
}
update accList;
}
}catch(Exception e) {
System.debug(e.getMessage());
response = 'Error sending emails';
}
return response;
}//what this method does is call the sendpdfgeneration method which is the method that generates and sends a custom email. After calling the methid, the email_sent__c field is updated to false
Any help in fixing my test method would be great;y appreciated. Thank you
I have written an Apex Batch schedulable class that runs a method from another class everyday at a certain time. What this batch class does is see all the accounts that have a field "Email Sent__c" as true and if it is true, it will pass those clients to the execute function so that it runs a method from a different class. this method basically generates an email and sends it. Once the email is sent, it updates the field Email_Sent__c to false. Everything works great and now in order to deploy it, I am writing some test classes. The problem is that the test class I have written for the Batch Apex only shows 50% coverage. Can someone please let me know why this is only 50% and what I can do to fix it? Also, I dont think the system.assert calls are checking the email_sent values after the update, they are only taking the values from the test setup method
Here is the Batch Apex class I wrote:
global class ConfirmationCardBatchApex implements Database.Batchable<sObject>, Database.Stateful {
global Database.QueryLocator start(Database.BatchableContext BC) {
Datetime clientReleasedDate = Datetime.now().addHours(-24);
return Database.getQueryLocator(
'SELECT Id, Client_Released__c, Client_Number__c, Release_Date__c, ' +
'Email_Sent__c FROM Account ' +
'WHERE Email_Sent__c = true AND Client_Released__c = true AND Release_Date__c<=:clientReleasedDate'
);
}
global void execute( Database.BatchableContext BC, List<Account> scope){
List<String> acctIdList = new List<String>();
for(Account account : scope){
acctIdList.add(account.Id);
}
LM_ChangeAccountRT.resendEmails(acctIdList);
}
global void finish(Database.BatchableContext bc){
System.debug( 'finish: called' );
}
}
The test class I wrote is the following (I am sure it has alot of mistakes. what can i do to get 100% coverage?)
@isTest
public class TestConfirmationCardBatchApex {
static Account client;
static Account client1;
static Account client2;
static Account parentC;
static Contact con;
@testSetup
Contact cont1 = new Contact(LastName='ContTest1', Email='test1contact@libertymutual.com', CommunicationType__c ='Holiday card', recordTypeId = Schema.SObjectType.contact.getRecordTypeInfosByName().get('Business Development Manager').getRecordTypeId(),FirstName= 'Contact');
insert cont1;
id tempuser = [Select id from User where LastName='Testing' limit 1].id;
system.debug('11111'+tempuser);
parentC = TestDataUtils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
parentC.Dealership_Partner__c = 'BMW';
parentC.Dealership_State__c='WA';
parentC.Name = 'Parent Name';
parentC.Client_Number__c = '12302.0';
parentC.Business_Development_Manager__c=cont1.id;
insert parentC;
client1 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client1.Name = 'Test Client 2';
client1.Business_Development_Manager__c=cont1.id;
client1.Branch_Manager__c = tempuser;
client1.Dealership_Partner__c = 'BMW';
client1.Dealership_State__c= 'TX';
client1.ParentID = parentC.Id;
client1.Client_Number__c = '12322.0';
client1.Email_Sent__c = true;
client1.Client_Released__c = true;
accountdata.add(client1);
client2 = TestDataUTils.createAccountFromRecordType(Schema.SObjectType.Account.getRecordTypeInfosByName().get('Referral Program - Participant Form').getRecordTypeId());
client2.Name = 'Test Client 3';
client2.Business_Development_Manager__c=cont1.id;
client2.Branch_Manager__c = tempuser;
client2.Dealership_Partner__c = 'BMW';
client2.Dealership_State__c= 'CA';
client2.ParentID = parentC.Id;
client2.Client_Number__c = '12332.0';
client2.Email_Sent__c = true;
client2.Client_Released__c = true;
accountdata.add(client2);
insert accountdata;
static testmethod void test() {
Test.startTest();
ConfirmationCardBatchApex confirm = new ConfirmationCardBatchApex();
Id batchId = Database.executeBatch(confirm);
Account emailTest = [SELECT Id, Name, Client_Released__c, Client_Number__c, Release_Date__c, Email_Sent__c FROM Account WHERE Name IN ('ContTest1', 'Test Client 1', 'Test Client 2') AND Email_Sent__c = true];
Test.stopTest();
System.assertEquals(true, emailTest.Email_Sent__c, 'Expected value should be true'); // After method is run, the email_sent__c should be false but it only shows success when I assert it to true.
}
}
In case you are wondering what this resendemails method is(in the LM_CHANGEACCOUNTRT Class), here is a snippet of it:
@AuraEnabled
public static String resendEmails(List<String> accountIdList) {
String response = null;
try {
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() ||
sysAdmin.Id == userinfo.getProfileId()) {
List<Account> accList = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,Existing_Participant__c,
Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,Client_Number__c,Closing_Manager__r.name,
Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,Is_a_broker_receiving_compensation__c,Broker__r.name,
,Broker__r.State__c, Email_Sent__c,
FROM Account
WHERE Id IN:accountIdList];
for(Account acc: accList){
if (acc.Client_Number__c != null && acc.Client_Released__c && acc.Email_Sent__c == true) {
sendpdfgenerationEmails(acc);
acc.Email_Sent__c = false;
response = 'Email Sent';
}else {
response= 'Access Denied';
}
}
update accList;
}
}catch(Exception e) {
System.debug(e.getMessage());
response = 'Error sending emails';
}
return response;
}//what this method does is call the sendpdfgeneration method which is the method that generates and sends a custom email. After calling the methid, the email_sent__c field is updated to false
Any help in fixing my test method would be great;y appreciated. Thank you
- Afzaal Hassan
- November 27, 2018
- Like
- 0
Run apex method after several days
Hello
I am a little stuck on this and am pretty sure I need to use a Schedule Apex Job for this but I am not sure how to modify my class or whether this is the best approach. I already have a class written, which works great. What the class does is that when a client record is created, an email sent to the client owner that displays some information and has some attachments. The reason why I wrote a class instead of workflow etc is because the apex class uses logic to determine what type of email body/template and attachment needs to be selected(based on the client's company). So the apex class generates that body and sends the email. The problem is due to a new business requirement. They want this email sent 2 DAYS AFTER the client is released/created. Here is a snippet of my code. Can someone please let me know what I need to do to use Schedule Apex, or perhaps modify it to use Process Builder? Please let me know what the best way is. I tried using the Schedule apex Trailhead and I am still confused.
global class LM_ChangeAccountRT {
@AuraEnabled
public static String resendEmails(String accountId) {
String response;
try {
Profile sysAdmin = [select id from profile where name='System Administrator'];
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() || sysAdmin.Id == userinfo.getProfileId()) {
Account acc = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,Existing_Participant__c,
Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,Client_Number__c,Closing_Manager__r.name,
Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,Is_a_broker_receiving_compensation__c,Broker__r.name,
Broker__r.Attention__c,Broker__r.Street_Address_1__c,Broker__r.Street_Address_2__c,Broker__r.ZipCode__c,Broker__r.City__c,Broker__r.State__c,
Broker__r.Special_Notes__c, Business_Development_Manager__r.Email, Branch_Manager__r.Email, Dealership_Spiff_Payment__c, Agent__c, Agent_Email__c, Territory_Manager__c, Territory_Manager_Email__c
FROM Account
WHERE Id=:accountId];
if (acc.Client_Number__c != null && acc.Client_Released__c) {
sendpdfgenerationEmails(acc);
response = 'Email Sent';
}
return response;
} else {
return 'Access Denied';
}
} catch(Exception e) {
System.debug(e.getMessage());
return 'Error sending emails';
}
}
// From Quick Action
@AuraEnabled
public static string updateAccountRecordType(String accountId,String rtName){
string errormsg;
try{
system.debug('ARMS_Business_User_ProfileId---------->'+System.Label.ARMS_Business_User_ProfileId);
if(System.Label.ARMS_Business_User_ProfileId == userinfo.getProfileId())
{
errormsg = 'Business_User';
}
else
{
Account acc = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,
Existing_Participant__c,Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,
Client_Number__c,Closing_Manager__r.name,Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,
Is_a_broker_receiving_compensation__c,BrokerPayee__r.name,BrokerPayee__r.Attention__c, BrokerPayee__c,
BrokerPayee__r.Street_Address_1__c,BrokerPayee__r.Street_Address_2__c,BrokerPayee__r.City__c,BrokerPayee__r.State__c,BrokerPayee__r.ZipCode__c,
BrokerPayee__r.Special_Notes__c, BrokerPayee__r.Is_this_a_new_broker__c, Dealership_Spiff_Payment__c, Business_Development_Manager__r.Email,
Branch_Manager__r.Email, Agent__c, Agent_Email__c, Territory_Manager__c, Territory_Manager_Email__c FROM Account WHERE Id=:accountId];
acc.RecordTypeId = [SELECT Id FROM RecordType WHERE DeveloperName =:rtName AND sObjectType = 'Account'].Id;
system.debug('acc.Client_Released__c---------->'+acc.Client_Released__c);
if(acc.Client_Number__c!=null){
if(rtName=='Client_Record' && acc.Client_Released__c==false){
acc.Client_Released__c=true;
}
update acc;
if(rtName=='Client_Record'){
sendpdfgenerationEmails(acc);
}
if(rtName=='Client_Form_Cancelled'){
//Call cancellation approval process
//Dev Note Lawrence - Why approval if it is been changed to cancel?? I don't think this makes sense.
Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
req1.setComments('Please approve client cancellation');
req1.setObjectId(acc.id);
req1.setProcessDefinitionNameOrId('LM_ClientCancelationAproval');
req1.setSkipEntryCriteria(true);
req1.setSubmitterId(acc.ownerid);
Approval.ProcessResult result = Approval.process(req1);
}
}
else{
errormsg = 'DisplayError';
}
}
return errormsg;
}
catch(Exception e){
system.debug(e.getMessage());
return null;
}
}
/*
* Method to send Confirmation card opt-in card by fetching visual force email template setup for different dealership.
*/
@AuraEnabled
public static void sendpdfgenerationEmails(Account acc){
system.debug('start of confirmation card and pdf generation');
//Logic to find which VF template is used to send an email.
list<EmailTemplate> templateId = new list<EmailTemplate>();
string temppartner;
String partner_opt_in_attachment;
boolean sendFCAmail;
List<Dealership_PDF_Generation__c> custsettingdata = Dealership_PDF_Generation__c.getall().values();
System.debug('custom setting size = ' + custsettingdata.size());
// Fetch State
if(acc.Dealership_State__c!=null && acc.Dealership_Partner__c!=null)
{
for(Dealership_PDF_Generation__c tempcustsetting :custsettingdata)
{
if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c && tempcustsetting.State__c=='WA' && acc.Dealership_State__c=='WA'){
//For WA State
// temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
}
else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c && tempcustsetting.State__c=='TX' && acc.Dealership_State__c=='TX'){
//For TX State
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
}
else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c!=tempcustsetting.State__c && tempcustsetting.State__c!='TX' && acc.Dealership_State__c!='TX' && acc.Dealership_State__c!='WA' &&tempcustsetting.State__c!='WA' ){
//For Non TX State
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
system.debug('grabbed template: ' + temppartner);
}
//else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c) {
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
// temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
// partner_opt_in_attachment = tempcustsetting.Opt_in_form__c;
// system.debug('grabbed template: ' + temppartner);
//}
}
}
if(acc.Dealership_Partner__c != null && temppartner!=null ){
system.debug('temppartner------------->'+temppartner);
if(temppartner.contains('FCA') && acc.FCA_Dealership__c==true){
sendFCAmail = true;
}
else if(!temppartner.contains('FCA')){
sendFCAmail = true;
}
else{
sendFCAmail = false;
}
// PWC originally used a LIKE in the where clause. That didn't work for the way we built the Service Program template.
templateId.add([Select id,DeveloperName from EmailTemplate where DeveloperName = :temppartner]);
}
if(templateId!=null && templateId.size() > 0 && sendFCAmail){
string accwhatid = acc.id;
string emailid = acc.owner.id;
string Supervisoremailid;
string BDMcontact;
string territoryManagerEmail = acc.Territory_Manager_Email__c;
string agentEmail = acc.Agent_Email__c;
if(acc.Branch_Manager__c!=null){
Supervisoremailid = acc.Branch_Manager__c;
}
if(acc.Business_Development_Manager__c!=null){
BDMcontact = acc.Business_Development_Manager__c;
}
list<Messaging.SingleEmailMessage> emails = new list<Messaging.SingleEmailMessage>();
if(emailid!=null && acc.Owner.Email!= null){
Messaging.SingleEmailMessage messageowner = new Messaging.SingleEmailMessage();
messageowner.setTemplateId(templateId[0].id); // Id of template that needs to rendered
messageowner.setTargetObjectId(emailid); // setTargetObjectId= user to which we need to send an email
messageowner.setSaveAsActivity(false); // This is set as false while calling from apex
messageowner.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(messageowner);
}
if(Supervisoremailid!=null && acc.Branch_Manager__r.Email != null){
Messaging.SingleEmailMessage messageSupervisor = new Messaging.SingleEmailMessage();
messageSupervisor.setTemplateId(templateId[0].id); // Id of template that needs to rendered
messageSupervisor.setTargetObjectId(Supervisoremailid); // setTargetObjectId= user to which we need to send an email
messageSupervisor.setSaveAsActivity(false);
messageSupervisor.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(messageSupervisor);
}
if(BDMcontact!=null && acc.Business_Development_Manager__r.email != null){
Messaging.SingleEmailMessage messageContact = new Messaging.SingleEmailMessage();
messageContact.setTemplateId(templateId[0].id); // Id of template that needs to rendered
messageContact.setTargetObjectId(BDMcontact); // setTargetObjectId= user to which we need to send an email
messageContact.setSaveAsActivity(false); // This is set as false while calling from apex
messageContact.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(messageContact);
}
if(acc.Dealership_Partner__c.contains('EAM Non-OEM') && territoryManagerEmail!=null && emailid!=null && acc.Owner.Email!= null){
Messaging.SingleEmailMessage agentMessage = new Messaging.SingleEmailMessage();
String[] toAgent = new String[] {agentEmail};
String[] tomEmail = new String[] {'Thomas.Papke@LibertyMutual.com'};
agentMessage.setTemplateId(templateId[0].id); // Id of template that needs to rendered
agentMessage.setTargetObjectId(emailid); // setTargetObjectId= user to which we need to send an email
agentMessage.setToAddresses(toAgent);
tomEmail.add(territoryManagerEmail);
agentMessage.setccAddresses(tomEmail);
agentMessage.setSaveAsActivity(false); // This is set as false while calling from apex
agentMessage.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(agentMessage);
}
// If available attach the opt-in card
if (partner_opt_in_attachment != null) {
StaticResource sr = [Select s.Name, s.Id, s.Body From StaticResource s where s.Name =: partner_opt_in_attachment]; // 'static_resource' is the name of the static resource PDF.
Blob tempBlob = sr.Body;
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
efa.setBody(tempBlob);
efa.setFileName('Opt-in.pdf');
List<Messaging.EmailFileAttachment> attachments = new List<Messaging.EmailFileAttachment>();
attachments.add(efa);
// add attachment to each email
for (Messaging.SingleEmailMessage email : emails) {
email.setFileAttachments(attachments);
}
}
system.debug('email sent: ' + emails.size());
Messaging.sendEmail(emails);
}
}
}
Thank you everyone for your help
I am a little stuck on this and am pretty sure I need to use a Schedule Apex Job for this but I am not sure how to modify my class or whether this is the best approach. I already have a class written, which works great. What the class does is that when a client record is created, an email sent to the client owner that displays some information and has some attachments. The reason why I wrote a class instead of workflow etc is because the apex class uses logic to determine what type of email body/template and attachment needs to be selected(based on the client's company). So the apex class generates that body and sends the email. The problem is due to a new business requirement. They want this email sent 2 DAYS AFTER the client is released/created. Here is a snippet of my code. Can someone please let me know what I need to do to use Schedule Apex, or perhaps modify it to use Process Builder? Please let me know what the best way is. I tried using the Schedule apex Trailhead and I am still confused.
global class LM_ChangeAccountRT {
@AuraEnabled
public static String resendEmails(String accountId) {
String response;
try {
Profile sysAdmin = [select id from profile where name='System Administrator'];
//Only send emails if user is either an ARMS Administor or System Administrator
if (System.label.ARMS_Administrator_Profile_Id == userinfo.getProfileId() || sysAdmin.Id == userinfo.getProfileId()) {
Account acc = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,Existing_Participant__c,
Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,Client_Number__c,Closing_Manager__r.name,
Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,Is_a_broker_receiving_compensation__c,Broker__r.name,
Broker__r.Attention__c,Broker__r.Street_Address_1__c,Broker__r.Street_Address_2__c,Broker__r.ZipCode__c,Broker__r.City__c,Broker__r.State__c,
Broker__r.Special_Notes__c, Business_Development_Manager__r.Email, Branch_Manager__r.Email, Dealership_Spiff_Payment__c, Agent__c, Agent_Email__c, Territory_Manager__c, Territory_Manager_Email__c
FROM Account
WHERE Id=:accountId];
if (acc.Client_Number__c != null && acc.Client_Released__c) {
sendpdfgenerationEmails(acc);
response = 'Email Sent';
}
return response;
} else {
return 'Access Denied';
}
} catch(Exception e) {
System.debug(e.getMessage());
return 'Error sending emails';
}
}
// From Quick Action
@AuraEnabled
public static string updateAccountRecordType(String accountId,String rtName){
string errormsg;
try{
system.debug('ARMS_Business_User_ProfileId---------->'+System.Label.ARMS_Business_User_ProfileId);
if(System.Label.ARMS_Business_User_ProfileId == userinfo.getProfileId())
{
errormsg = 'Business_User';
}
else
{
Account acc = [SELECT Id,FCA_Dealership__c,Branch_Manager__c,Business_Development_Manager__c,Client_Released__c,
Existing_Participant__c,Dealership_Partner__c,Dealership_State__c,RecordTypeId,owner.email,owner.Supervisor_Email__c,
Client_Number__c,Closing_Manager__r.name,Name,Completed_Date__c,Effective_Date__c,Closing_Manager__c,Is_the_client_receiving_compensation__c,
Is_a_broker_receiving_compensation__c,BrokerPayee__r.name,BrokerPayee__r.Attention__c, BrokerPayee__c,
BrokerPayee__r.Street_Address_1__c,BrokerPayee__r.Street_Address_2__c,BrokerPayee__r.City__c,BrokerPayee__r.State__c,BrokerPayee__r.ZipCode__c,
BrokerPayee__r.Special_Notes__c, BrokerPayee__r.Is_this_a_new_broker__c, Dealership_Spiff_Payment__c, Business_Development_Manager__r.Email,
Branch_Manager__r.Email, Agent__c, Agent_Email__c, Territory_Manager__c, Territory_Manager_Email__c FROM Account WHERE Id=:accountId];
acc.RecordTypeId = [SELECT Id FROM RecordType WHERE DeveloperName =:rtName AND sObjectType = 'Account'].Id;
system.debug('acc.Client_Released__c---------->'+acc.Client_Released__c);
if(acc.Client_Number__c!=null){
if(rtName=='Client_Record' && acc.Client_Released__c==false){
acc.Client_Released__c=true;
}
update acc;
if(rtName=='Client_Record'){
sendpdfgenerationEmails(acc);
}
if(rtName=='Client_Form_Cancelled'){
//Call cancellation approval process
//Dev Note Lawrence - Why approval if it is been changed to cancel?? I don't think this makes sense.
Approval.ProcessSubmitRequest req1 = new Approval.ProcessSubmitRequest();
req1.setComments('Please approve client cancellation');
req1.setObjectId(acc.id);
req1.setProcessDefinitionNameOrId('LM_ClientCancelationAproval');
req1.setSkipEntryCriteria(true);
req1.setSubmitterId(acc.ownerid);
Approval.ProcessResult result = Approval.process(req1);
}
}
else{
errormsg = 'DisplayError';
}
}
return errormsg;
}
catch(Exception e){
system.debug(e.getMessage());
return null;
}
}
/*
* Method to send Confirmation card opt-in card by fetching visual force email template setup for different dealership.
*/
@AuraEnabled
public static void sendpdfgenerationEmails(Account acc){
system.debug('start of confirmation card and pdf generation');
//Logic to find which VF template is used to send an email.
list<EmailTemplate> templateId = new list<EmailTemplate>();
string temppartner;
String partner_opt_in_attachment;
boolean sendFCAmail;
List<Dealership_PDF_Generation__c> custsettingdata = Dealership_PDF_Generation__c.getall().values();
System.debug('custom setting size = ' + custsettingdata.size());
// Fetch State
if(acc.Dealership_State__c!=null && acc.Dealership_Partner__c!=null)
{
for(Dealership_PDF_Generation__c tempcustsetting :custsettingdata)
{
if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c && tempcustsetting.State__c=='WA' && acc.Dealership_State__c=='WA'){
//For WA State
// temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
}
else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c==tempcustsetting.State__c && tempcustsetting.State__c=='TX' && acc.Dealership_State__c=='TX'){
//For TX State
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
}
else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c && acc.Dealership_State__c!=tempcustsetting.State__c && tempcustsetting.State__c!='TX' && acc.Dealership_State__c!='TX' && acc.Dealership_State__c!='WA' &&tempcustsetting.State__c!='WA' ){
//For Non TX State
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
if(acc.Dealership_Spiff_Payment__c == '% premium'){
partner_opt_in_attachment=tempcustsetting.opt_in_form_premium__c;
}else{
partner_opt_in_attachment=tempcustsetting.opt_in_form_nonpremium__c;
}
system.debug('grabbed template: ' + temppartner);
}
//else if(acc.Dealership_Partner__c == tempcustsetting.Dealership_Partner__c) {
//temppartner= '%' + tempcustsetting.TEMPLATE_Unique_name__c + '%';
// temppartner= tempcustsetting.TEMPLATE_Unique_name__c;
// partner_opt_in_attachment = tempcustsetting.Opt_in_form__c;
// system.debug('grabbed template: ' + temppartner);
//}
}
}
if(acc.Dealership_Partner__c != null && temppartner!=null ){
system.debug('temppartner------------->'+temppartner);
if(temppartner.contains('FCA') && acc.FCA_Dealership__c==true){
sendFCAmail = true;
}
else if(!temppartner.contains('FCA')){
sendFCAmail = true;
}
else{
sendFCAmail = false;
}
// PWC originally used a LIKE in the where clause. That didn't work for the way we built the Service Program template.
templateId.add([Select id,DeveloperName from EmailTemplate where DeveloperName = :temppartner]);
}
if(templateId!=null && templateId.size() > 0 && sendFCAmail){
string accwhatid = acc.id;
string emailid = acc.owner.id;
string Supervisoremailid;
string BDMcontact;
string territoryManagerEmail = acc.Territory_Manager_Email__c;
string agentEmail = acc.Agent_Email__c;
if(acc.Branch_Manager__c!=null){
Supervisoremailid = acc.Branch_Manager__c;
}
if(acc.Business_Development_Manager__c!=null){
BDMcontact = acc.Business_Development_Manager__c;
}
list<Messaging.SingleEmailMessage> emails = new list<Messaging.SingleEmailMessage>();
if(emailid!=null && acc.Owner.Email!= null){
Messaging.SingleEmailMessage messageowner = new Messaging.SingleEmailMessage();
messageowner.setTemplateId(templateId[0].id); // Id of template that needs to rendered
messageowner.setTargetObjectId(emailid); // setTargetObjectId= user to which we need to send an email
messageowner.setSaveAsActivity(false); // This is set as false while calling from apex
messageowner.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(messageowner);
}
if(Supervisoremailid!=null && acc.Branch_Manager__r.Email != null){
Messaging.SingleEmailMessage messageSupervisor = new Messaging.SingleEmailMessage();
messageSupervisor.setTemplateId(templateId[0].id); // Id of template that needs to rendered
messageSupervisor.setTargetObjectId(Supervisoremailid); // setTargetObjectId= user to which we need to send an email
messageSupervisor.setSaveAsActivity(false);
messageSupervisor.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(messageSupervisor);
}
if(BDMcontact!=null && acc.Business_Development_Manager__r.email != null){
Messaging.SingleEmailMessage messageContact = new Messaging.SingleEmailMessage();
messageContact.setTemplateId(templateId[0].id); // Id of template that needs to rendered
messageContact.setTargetObjectId(BDMcontact); // setTargetObjectId= user to which we need to send an email
messageContact.setSaveAsActivity(false); // This is set as false while calling from apex
messageContact.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(messageContact);
}
if(acc.Dealership_Partner__c.contains('EAM Non-OEM') && territoryManagerEmail!=null && emailid!=null && acc.Owner.Email!= null){
Messaging.SingleEmailMessage agentMessage = new Messaging.SingleEmailMessage();
String[] toAgent = new String[] {agentEmail};
String[] tomEmail = new String[] {'Thomas.Papke@LibertyMutual.com'};
agentMessage.setTemplateId(templateId[0].id); // Id of template that needs to rendered
agentMessage.setTargetObjectId(emailid); // setTargetObjectId= user to which we need to send an email
agentMessage.setToAddresses(toAgent);
tomEmail.add(territoryManagerEmail);
agentMessage.setccAddresses(tomEmail);
agentMessage.setSaveAsActivity(false); // This is set as false while calling from apex
agentMessage.setWhatId(accwhatid); // Whatid is the ID of account used in template for merge fields
emails.add(agentMessage);
}
// If available attach the opt-in card
if (partner_opt_in_attachment != null) {
StaticResource sr = [Select s.Name, s.Id, s.Body From StaticResource s where s.Name =: partner_opt_in_attachment]; // 'static_resource' is the name of the static resource PDF.
Blob tempBlob = sr.Body;
Messaging.EmailFileAttachment efa = new Messaging.EmailFileAttachment();
efa.setBody(tempBlob);
efa.setFileName('Opt-in.pdf');
List<Messaging.EmailFileAttachment> attachments = new List<Messaging.EmailFileAttachment>();
attachments.add(efa);
// add attachment to each email
for (Messaging.SingleEmailMessage email : emails) {
email.setFileAttachments(attachments);
}
}
system.debug('email sent: ' + emails.size());
Messaging.sendEmail(emails);
}
}
}
Thank you everyone for your help
- Afzaal Hassan
- October 31, 2018
- Like
- 0
Move recordType query out of loop
I have a trigger written that basically looks at the record type and for each account in that record type, checks/validates to see if the field is entered by user or not. The trigger works, however I put a query inside the for loop, which I realized is bad practice when I started to recieve System.Exception Limit errors. Can someone please help me rewrite this. Whats throwing me off is that the trigger has a RecordType object and I have not worked with that before.
trigger CancelledBrokerValidation on Account (before update) [
for (Account acc : Trigger.new) {
List<RecordType> test = [SELECT Name FROM RecordType where Id =: acc.RecordTypeId];
System.debug('RecordType size: '+test.size());
if (!test.isEmpty()) {
System.debug('RecordType: '+test[0].Name);
if ((acc.Email_Templates__c == '' || acc.Email_Templates__c == null) && test[0].Name == 'Client Form Cancelled' && acc.Payee_Type__c == 'Broker') {
System.debug('Final Step: Field is required');
acc.Email_Templates__c.addError('Cancelled Broker Email Template Field is required.');
}
}
}
}
I tried to take a crack at rewriting this but am stuck. This is what I have done so far:
trigger CancelledBrokerValidation on Account (before update) {
List<RecordType> accountRecords = [SELECT Id, Name FROM RecordType where Id IN :Trigger.newMap.keySet()];
//Map<Id,RecordType> accountRecords = new Map<Id,RecordType>([Select id,Name from RecordType where Id IN: Trigger.newMap.keySet()]);
List<Account> accountsToupdate = new List <Account>();
Map<Id, RecordType> clientToRecordMap = new Map<Id, RecordType>();
for(Account acc : accountRecords){
System.debug('RecordType size: '+acc.size());
}
}
Thats why I was saying I am confused with the recordType object because the for loop is not correct and recordType doesnt seem to have a size object (throwing that error)
Any help will be greatly appreciated
Thank you
trigger CancelledBrokerValidation on Account (before update) [
for (Account acc : Trigger.new) {
List<RecordType> test = [SELECT Name FROM RecordType where Id =: acc.RecordTypeId];
System.debug('RecordType size: '+test.size());
if (!test.isEmpty()) {
System.debug('RecordType: '+test[0].Name);
if ((acc.Email_Templates__c == '' || acc.Email_Templates__c == null) && test[0].Name == 'Client Form Cancelled' && acc.Payee_Type__c == 'Broker') {
System.debug('Final Step: Field is required');
acc.Email_Templates__c.addError('Cancelled Broker Email Template Field is required.');
}
}
}
}
I tried to take a crack at rewriting this but am stuck. This is what I have done so far:
trigger CancelledBrokerValidation on Account (before update) {
List<RecordType> accountRecords = [SELECT Id, Name FROM RecordType where Id IN :Trigger.newMap.keySet()];
//Map<Id,RecordType> accountRecords = new Map<Id,RecordType>([Select id,Name from RecordType where Id IN: Trigger.newMap.keySet()]);
List<Account> accountsToupdate = new List <Account>();
Map<Id, RecordType> clientToRecordMap = new Map<Id, RecordType>();
for(Account acc : accountRecords){
System.debug('RecordType size: '+acc.size());
}
}
Thats why I was saying I am confused with the recordType object because the for loop is not correct and recordType doesnt seem to have a size object (throwing that error)
Any help will be greatly appreciated
Thank you
- Afzaal Hassan
- June 04, 2018
- Like
- 0
populate field of an object by value from another object
Hello
I have a field called "Contract Email 2" in the Account object. I want this field to be filled with the email that is on the field "Contract Email" in the Payee object. It shouls also update if that Payee object email changes. I wrote this trigger but my Contract Email 2 is always blank and not filling with the email that is on the Payee object. Can someone please help with this? My trigger is below:
So I am taking this step by step. For now, if someone changes or adds the contract email in Payee__c, I would like that email address/value to populate the field "Contract_Email_2" in the Account object. I wrote the following trigger, but the field in the account object is not working. Any ideas why?
trigger PayeeUpdateOnAccount on Payee__c (after update) {
List<Payee_Client_Agreements__c> pcaList = [SELECT ID, Payee_Type__c, Payee__r.Contract_Email__c, Client__c from Payee_Client_Agreements__c WHERE Payee_ID__c IN :Trigger.newMap.keyset()];
List<Account> accountsToupdate = new List <Account>();
Map<Id, Payee_Client_Agreements__c> clientToPcaMap = new Map<Id, Payee_Client_Agreements__c>();
for(Payee_Client_Agreements__c pca : pcaList){
if(pca.Payee_Type__c == 'Broker'){
clientToPcaMap.put(pca.Client__c, pca);
}
}
List<Account> acctList = [SELECT ID, Contract_Email_2__c from Account Where ID IN :clientToPcaMap.keySet()];
for( Account acct : acctList ){
if(acct.Contract_Email_2__c != clientToPcaMap.get(acct.Id).Payee__r.Contract_Email__c){
acct.Contract_Email_2__c = clientToPcaMap.get(acct.Id).Payee__r.Contract_Email__c;
accountsToupdate.add(acct);
}
}
if (accountsToupdate.isEmpty()){
update accountsToupdate;
}
/**for (Payee__c py : Trigger.new) {
String payeeID = py.Payee_ID__c;
//List<Payee_Client_Agreements__c> pcaList = [SELECT ID, Payee_Type__c, Payee__r.Contract_Email__c from Payee_Client_Agreements__c where Payee_ID__c =: payeeID];
if(!pcaList.isEmpty()){
for (Payee_Client_Agreements__c pObj : pcaList) {
update pObj;
}
}
} **/
}
I have a field called "Contract Email 2" in the Account object. I want this field to be filled with the email that is on the field "Contract Email" in the Payee object. It shouls also update if that Payee object email changes. I wrote this trigger but my Contract Email 2 is always blank and not filling with the email that is on the Payee object. Can someone please help with this? My trigger is below:
So I am taking this step by step. For now, if someone changes or adds the contract email in Payee__c, I would like that email address/value to populate the field "Contract_Email_2" in the Account object. I wrote the following trigger, but the field in the account object is not working. Any ideas why?
trigger PayeeUpdateOnAccount on Payee__c (after update) {
List<Payee_Client_Agreements__c> pcaList = [SELECT ID, Payee_Type__c, Payee__r.Contract_Email__c, Client__c from Payee_Client_Agreements__c WHERE Payee_ID__c IN :Trigger.newMap.keyset()];
List<Account> accountsToupdate = new List <Account>();
Map<Id, Payee_Client_Agreements__c> clientToPcaMap = new Map<Id, Payee_Client_Agreements__c>();
for(Payee_Client_Agreements__c pca : pcaList){
if(pca.Payee_Type__c == 'Broker'){
clientToPcaMap.put(pca.Client__c, pca);
}
}
List<Account> acctList = [SELECT ID, Contract_Email_2__c from Account Where ID IN :clientToPcaMap.keySet()];
for( Account acct : acctList ){
if(acct.Contract_Email_2__c != clientToPcaMap.get(acct.Id).Payee__r.Contract_Email__c){
acct.Contract_Email_2__c = clientToPcaMap.get(acct.Id).Payee__r.Contract_Email__c;
accountsToupdate.add(acct);
}
}
if (accountsToupdate.isEmpty()){
update accountsToupdate;
}
/**for (Payee__c py : Trigger.new) {
String payeeID = py.Payee_ID__c;
//List<Payee_Client_Agreements__c> pcaList = [SELECT ID, Payee_Type__c, Payee__r.Contract_Email__c from Payee_Client_Agreements__c where Payee_ID__c =: payeeID];
if(!pcaList.isEmpty()){
for (Payee_Client_Agreements__c pObj : pcaList) {
update pObj;
}
}
} **/
}
- Afzaal Hassan
- May 24, 2018
- Like
- 0
Put another object value in workflow
I have an Account object that includes another "Payee Agreement" object. In that Payee Agreement Object is a List of "Payee" objects. My issue is that I had created a workflow that tries to send an email to the email address listed in the "Contract Email" field in the Payee object. So if that Account has 3 Payee Agreeements listed, then I need to obtain the three different "Contract emails" listed in the Payee object and send the email to those three address. Obviously, my current workflow cant do that because workflows cant do cross objects. What I did was created another field in Account called "Contract Email 2". Then I tried to update this field with the list of email values in Payee through a trigger. I dont think I wrote the trigger correct. For one, I think I have the list generated correctly, but I dont think I am physically updating this ACCOUNT field. Also, how do I properly create the "Contract Email 2" field because my understanding is that it will not fill it with a list of values, correct? My trigger is below (if its even needed). If I am doing this whole thing the wrong way, please let me know how I should restart this problem. If I need to explain this problem clearer, please let me know as well. Essentially, I am just hoping that a correct "list" shows up when I select the "recipient" section in my workflow.
trigger PayeeCntractEmail on Payee_Client_Agreements__c (before insert, after update, before delete, after delete) {
List<Account> accountemailList = new List<Account>();
String clientNumber = '';
for (Payee_Client_Agreements__c pca : Trigger.New) {
String payeeAgreementID = pca.Payee_ID__c;
clientNumber = pca.Client_Number__c;
Account aObj = [SELECT ID, Contract_Email__c from Account WHERE Client_Number__c =: clientNumber];
List<Payee__c> contractEmailList = [SELECT Contract_Email__c, Payee_Type__c from Payee__c WHERE Payee_ID__c =: payeeAgreementID];
for(Payee__c email: contractEmailList){
if(email.Payee_Type__c == 'Broker'){
aObj.Contract_Email__c = email.Contract_Email__c;
accountemailList.add(aObj);
}
}
update accountemailList;
//update aObj.Contract_Email__c;
}
}
trigger PayeeCntractEmail on Payee_Client_Agreements__c (before insert, after update, before delete, after delete) {
List<Account> accountemailList = new List<Account>();
String clientNumber = '';
for (Payee_Client_Agreements__c pca : Trigger.New) {
String payeeAgreementID = pca.Payee_ID__c;
clientNumber = pca.Client_Number__c;
Account aObj = [SELECT ID, Contract_Email__c from Account WHERE Client_Number__c =: clientNumber];
List<Payee__c> contractEmailList = [SELECT Contract_Email__c, Payee_Type__c from Payee__c WHERE Payee_ID__c =: payeeAgreementID];
for(Payee__c email: contractEmailList){
if(email.Payee_Type__c == 'Broker'){
aObj.Contract_Email__c = email.Contract_Email__c;
accountemailList.add(aObj);
}
}
update accountemailList;
//update aObj.Contract_Email__c;
}
}
- Afzaal Hassan
- May 24, 2018
- Like
- 0
using javascript within <script> tag
I want to insert a value generated from javascript to visualforce page, but it does not work. Here's my sample code (my real task is to do some calculation in <script>, so I simply cannot tape in apex tag directly):
Could anyone help?
I know a lot answers are using javascript as a static file... but I still want to use it here within this page.
Thank you!
<apex:page controller="CAReportAvgFine" > <apex:sectionheader title="Compliance Advisory Report" subtitle="Saved Penalty"/> <apex:outputText id="fine"> 76534</apex:outputText> <script> document.getElementByID("{!$Component.fine}").innerHTML= "8965478" ; </script> <style></style> </apex:page>
Could anyone help?
I know a lot answers are using javascript as a static file... but I still want to use it here within this page.
Thank you!
- Anna Lu 6
- November 09, 2017
- Like
- 0