Hello, Trailblazers. In this blog post, we will learn how to write an Apex Trigger for Custom Validations.
Acceptance Criteria: Write an Apex Trigger to restrict the Payment until the Final Quote is “Approved”.
To solve this, we have custom objects named Payment__c and Final_Quote__c in a lookup relationship with each other. Its lookup field name is “Quote__c”. On the Final_Quote__c object, there is a custom picklist field named Status__c. If the quote’s status is not “Approved”, then the user should not make payment.
So, let’s get started…
Apex Trigger for Custom Validation:
trigger paymentRestrictionTrigger on Payment__c(before insert, after insert){
if(trigger.isInsert && trigger.isBefore){
for(Payment__c pay : trigger.new){
if(pay. Quote__c!= null){
Final_Quote__c quo = [SELECT Id, Status__c FROM Final_Quote__c WHERE Id = :pay. Quote__c];
if(quo.Status__c != 'APPROVED'){
pay.addError('You can not create payment, because this Quote is not Approved yet. Thank You !!');
trigger paymentRestrictionTrigger on Payment__c (before insert, after insert) {
if(trigger.isInsert && trigger.isBefore){
for(Payment__c pay : trigger.new){
if(pay. Quote__c!= null){
Final_Quote__c quo = [SELECT Id, Status__c FROM Final_Quote__c WHERE Id = :pay. Quote__c];
if(quo.Status__c != 'APPROVED'){
pay.addError('You can not create payment, because this Quote is not Approved yet. Thank You !!');
}
}
}
}
}
trigger paymentRestrictionTrigger on Payment__c (before insert, after insert) {
if(trigger.isInsert && trigger.isBefore){
for(Payment__c pay : trigger.new){
if(pay. Quote__c!= null){
Final_Quote__c quo = [SELECT Id, Status__c FROM Final_Quote__c WHERE Id = :pay. Quote__c];
if(quo.Status__c != 'APPROVED'){
pay.addError('You can not create payment, because this Quote is not Approved yet. Thank You !!');
}
}
}
}
}
In this example:
- We defined the trigger on the Payment__c object and set it to run before records get inserted (before insert).
- Each Payment__c record in the batch will be inserted and checked if the Quote__c field on the Payment__c record is not null.
- After this, it fetches the Final_Quote__c records related to the Payment__c records with the help of SOQL query.
- It checks whether the quote’s status is “Approved” or not. If not, it throws an error.
Test Class for Apex Trigger:
Let’s write a test class for the above Apex Trigger. In this test class, we’ll cover both positive and negative scenarios.
publicclass PaymentRestrictionTriggerTest {
staticvoidtestPaymentCreationNotAllowed(){
// Create a test Final Quote with a non-approved status
Final_Quote__c testQuote = newFinal_Quote__c(Status__c = 'Pending');
// Create a test Payment related to the non-approved Final Quote
Payment__c testPayment = newPayment__c(Quote__c = testQuote.Id);
// If the trigger logic is correct, the payment insert should throw an exception
System.assert(false, 'Exception should have been thrown');
// Ensure that the expected exception message is thrown
System.assertEquals('You can not create payment, because this Quote is not Approved yet. Thank You !!', e.getMessage());
staticvoidtestPaymentCreationAllowed(){
// Create a test Final Quote with an approved status
Final_Quote__c testQuote = newFinal_Quote__c(Status__c = 'APPROVED');
// Create a test Payment related to the approved Final Quote
Payment__c testPayment = newPayment__c(Quote__c = testQuote.Id);
// If the trigger logic is correct, no exception should be thrown
System.assert(true, 'No exception should have been thrown');
// If an exception is thrown, fail the test
System.assert(false, 'Unexpected exception: ' + e.getMessage());
@isTest
public class PaymentRestrictionTriggerTest {
@isTest
static void testPaymentCreationNotAllowed() {
// Create a test Final Quote with a non-approved status
Final_Quote__c testQuote = new Final_Quote__c(Status__c = 'Pending');
insert testQuote;
// Create a test Payment related to the non-approved Final Quote
Payment__c testPayment = new Payment__c(Quote__c = testQuote.Id);
Test.startTest();
try {
// Insert the Payment
insert testPayment;
// If the trigger logic is correct, the payment insert should throw an exception
System.assert(false, 'Exception should have been thrown');
} catch (Exception e) {
// Ensure that the expected exception message is thrown
System.assertEquals('You can not create payment, because this Quote is not Approved yet. Thank You !!', e.getMessage());
}
Test.stopTest();
}
@isTest
static void testPaymentCreationAllowed() {
// Create a test Final Quote with an approved status
Final_Quote__c testQuote = new Final_Quote__c(Status__c = 'APPROVED');
insert testQuote;
// Create a test Payment related to the approved Final Quote
Payment__c testPayment = new Payment__c(Quote__c = testQuote.Id);
Test.startTest();
try {
// Insert the Payment
insert testPayment;
// If the trigger logic is correct, no exception should be thrown
System.assert(true, 'No exception should have been thrown');
} catch (Exception e) {
// If an exception is thrown, fail the test
System.assert(false, 'Unexpected exception: ' + e.getMessage());
}
Test.stopTest();
}
}
@isTest
public class PaymentRestrictionTriggerTest {
@isTest
static void testPaymentCreationNotAllowed() {
// Create a test Final Quote with a non-approved status
Final_Quote__c testQuote = new Final_Quote__c(Status__c = 'Pending');
insert testQuote;
// Create a test Payment related to the non-approved Final Quote
Payment__c testPayment = new Payment__c(Quote__c = testQuote.Id);
Test.startTest();
try {
// Insert the Payment
insert testPayment;
// If the trigger logic is correct, the payment insert should throw an exception
System.assert(false, 'Exception should have been thrown');
} catch (Exception e) {
// Ensure that the expected exception message is thrown
System.assertEquals('You can not create payment, because this Quote is not Approved yet. Thank You !!', e.getMessage());
}
Test.stopTest();
}
@isTest
static void testPaymentCreationAllowed() {
// Create a test Final Quote with an approved status
Final_Quote__c testQuote = new Final_Quote__c(Status__c = 'APPROVED');
insert testQuote;
// Create a test Payment related to the approved Final Quote
Payment__c testPayment = new Payment__c(Quote__c = testQuote.Id);
Test.startTest();
try {
// Insert the Payment
insert testPayment;
// If the trigger logic is correct, no exception should be thrown
System.assert(true, 'No exception should have been thrown');
} catch (Exception e) {
// If an exception is thrown, fail the test
System.assert(false, 'Unexpected exception: ' + e.getMessage());
}
Test.stopTest();
}
}
The above test class covers two scenarios:
- testPaymentCreationNotAllowed: It tests that attempting to create a Payment__c record related to a non-approved Final_Quote__c record will throw the expected exception.
- testPaymentCreationAllowed: It tests that creating a Payment__c record related to an approved Final_Quote__c record will not throw any exceptions.
Conclusion:
Thus, this blog post taught us how to write an Apex Trigger for Custom Validation.
References:
Batch Apex in Salesforce
Asynchronous Apex in Salesforce
You can also read :
- An Introduction to Salesforce CPQ
- Salesforce CPQ and its Key Features
- Unlocking the Power of AI: Einstein for Developers
- Revolutionizing Customer Engagement: The Salesforce Einstein Chatbot