function readOnly(count){ }
Starting November 20, the site will be set to read-only. On December 4, 2023,
forum discussions will move to the Trailblazer Community.
+ Start a Discussion
Heather  MickeyHeather Mickey 

apex trigger on Object B to allow/deny record create/update/delete based on sum of field in Object A

Hi,

I am very (read very) new to apex and am trying to create a trigger.

Object A:
id
date
hours
ownerid

Object B:
id
date
modify date
ownerid

Trigger to occur on Object B upon create, update, delete:

The Object B: ownerid wants to create, update or delete a record on Object B for date >= today() or modify_date >= today()

In order to allow the create, update, delete of record on Object B, the same ownerid of Object A must have a sum of X hours for date = last_week on Object A

If sum is < X hours, then create an error message that states X hours are not complete and do not allow create, update, delete of record on Object B.

How would I go about scripting this?

Thank you so, so much for helping my pursuit to learn apex! I truly appreciate it.
Shashikant SharmaShashikant Sharma
Your code flow should be :

1. Trigger on before insert, before update, before delete on Object B
2. Loop over all records in trigger.new ( Object B Record List )
3. Create a Set<Id> setOwnerId
4. Fetch all the records from Object A where OwnerId in setOwnerId and date > Date.today().addDays(-7)
5. Loop over the results of 4 and create a MAP<Id, List<Object A Record>> mapOwnerIdToListOfObjectARecord
6. Loop over in 5 and check if total for the items in the map is > 10 hours and create another  Map<Id, Boolean> mapOwnerIdToAllowDML
7. Loop over trigger.new ( Object B Record List ) and fetch Value mapOwnerIdToAllowDML to know if to show error or allow dml.

see this for developing trigger : http://forceschool.blogspot.in/search/label/Apex%20Triggers


 
BalajiRanganathanBalajiRanganathan
You have to use aggregate soql queries to achive this. you can try below template code
 
trigger sample on objectb__c (before insert, before delete, before update) {

  List<objectb__c > objList = Trigger.isDelete ? Trigger.old : Trigger.new;
  Set<id> ownerSet = new Set<id>();

  for (objectb__c  rec : objList ) {
       ownerSet.add(rec.ownerid);
  }

 Map<Id,AggregateResult> results = new Map<id,AggregateResult>([SELECT OwnerId id, SUM(hours__c) hour FROM 
   ObjectA__c WHERE ownerid in :ownerSet and date__c = LAST_WEEK group by ownerid]);

 for (objectb__c rec : objList ) { 
   AggregateResult result = results.get(rec.ownerid);
   if (result.get('hours') < X) {
     rec.addError('Error messgae');
   }
 }
}

 
Heather  MickeyHeather Mickey
Hi @BalajiRanganathan

Thank you. I keep getting an error on line 15. I have tried to update it to hour (like line 10) and with and without the ' ' around hour. I thought I understood the code and logic, but I don't understand Maps and AggregateResults enough to know what I am doing incorrectly. Would you know why this isn't working?

I get the following errors when trying either way:

if (result.get('hour') < 40) {
//error Inequality operator not allowed for this type: Object

if (result.get(hour) < 40) {
Variable does not exist: hour

Thank you so very much,
Heather
BalajiRanganathanBalajiRanganathan
Try

if ( Integer.valueOf(result.get('hour')) < 40 ) {
Heather  MickeyHeather Mickey
@BalajiRanganathan  -- you are a GENIUS!

I've been working on a test class when I realized I need the trigger to ignore when the user is a System Administrator. (Therefore, a Sys Admin can Create, Update, Delete regardless of anything/Object A.) We have a few Sys Admins and I tried to keep it dynamic. I'm not getting any "Problems", but I don't feel the script is correct because I am limiting the Profile adminId to 1.
trigger sample on objectb__c (before insert, before delete, before update) {
  Profile adminId = [SELECT Id FROM Profile WHERE Name='System Administrator' LIMIT 1];
  
  List<objectb__c > objList = Trigger.isDelete ? Trigger.old : Trigger.new;
  Set<id> ownerSet = new Set<id>();
 
  for (objectb__c  rec : objList ) {
       ownerSet.add(rec.ownerid);
  }
 
 Map<Id,AggregateResult> results = new Map<id,AggregateResult>([SELECT OwnerId id, SUM(hours__c) hour FROM
   ObjectA__c WHERE ownerid in :ownerSet and date__c = LAST_WEEK group by ownerid]);
 
 for (objectb__c rec : objList ) {
   AggregateResult result = results.get(rec.ownerid);
   if ( Integer.valueOf(result.get('hour')) < 40 && to.get('OwnerId') != adminId.Id) {
     rec.addError('Error message');
   }
 }
}

I appreciate all of your help (both in the script and in my learning).

Thank you again!




 
BalajiRanganathanBalajiRanganathan
adminId is the Id for the profile not for individual user. so you should not check it with owner id.
UserInfo class give detail about current user.

You can try below code. it will allow all the user who has System Administrator profile to update.
if ( Integer.valueOf(result.get('hour')) < 40 && UserInfo.getProfileId() != adminId.Id) {