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
forawormforaworm 

Validation

Hi,

 

I have a customized object  named  Demo  as a container for another object named Demo-Product. A Demo record can have one or more Demo-Products. Each Demo-Product can be part of many Demo records. Our customers can rent a Demo-Product for example for 30 days. 

 

If I add a Demo-Product to a Demo record for a particular customer I need an automatic check for the availability of the Demo-Product.

 

Sample:

 

Customer Micro Ltd. has Demo-Product xy1 from 10/15/2009 to 11/14/2009

Customer Masters Ltd. wants Demo-Product xy1 from 11/01/2009 to 11/30/2009

 

In such a case I need a notification for the User if he is trying to add the Demo-Product xy1 to a new or existing  Demo-Record. A message like "Demo-Product xy1 is occupied until 11/14/2009!" should appear. So I need to check all Demo-Products xy1 in all Demo records for a given time period.

 

I think I have to do it with Apex, however I have no experiences in Apex until yet.  I need a quick-tutorial to solve this issue with Apex and data access to the records.  Or is there any other posibility to solve this problem.

 

Thanks. 

CaptainObviousCaptainObvious

You have a Demo object containing customer information and a Demo-Product object containing product information...

I would suggest creating a third object and calling it Demo Rentals (for example). This object would be used to associate the Demo-Product to the Demo and to enter the date information.

In this third object, add the two lookup fields:
Demo (lookup to Demo)
Demo Product (lookup to Demo Product)
and two Date fields:
Start Date
End Date

Make the Demo Rental related list available on the Demo and Demo Product page layouts.

Now for the Apex trigger (add this to the Demo Rental object):

trigger checkDemoAvailability on Demo_Rental__c (before insert,before update) { Set<ID> DemoProductIDs = new Set<ID>{}; for(Demo_Rental__c demoRental:Trigger.new){ if(demoRental.Demo_Product__c!=null) { DemoProductIDs.add(demoRental.Demo_Product__c); } } if(DemoProductIDs.size() > 0){ //Retrieve all Rentals with the specified Demo-Product. Map<ID,Demo_Rental__c> DemoRentalFields = new Map<ID,Demo_Rental__c>([ Select Id, Demo__c, Demo_Product__c, Start_Date__c, End_Date__c From Demo_Rental__c Where Demo_Product__c in:DemoProductIDs]); //Keep track of the 'lowest' and 'highest' rental dates... //...this ensures that there is no date overlap across 'Demo Rental' records Date lowestDate; Date highestDate; for(Demo_Rental__c newRental : Trigger.new){ //initialize the lowest and highest dates lowestDate = newRental.Start_Date__c; highestDate = newRental.End_Date__c; //Loop through all rental records with the same demo product for(Demo_Rental__c oldRentals : DemoRentalFields.Values()) { if (oldRentals.Start_Date__c<lowestDate) { lowestDate=oldRentals.Start_Date__c; } if (oldRentals.End_Date__c>highestDate) { highestDate=oldRentals.End_Date__c; } //Adjust the Date-checking logic here (additional logic may be needed) if ( (newRental.Start_Date__c<=oldRentals.Start_Date__c && newRental.End_Date__c>=oldRentals.Start_Date__c ) || (newRental.Start_Date__c>=oldRentals.Start_Date__c && newRental.End_Date__c<=oldRentals.End_Date__c) || (newRental.Start_Date__c>lowestDate && newRental.End_Date__c<highestDate) ) { //Customize Error here newRental.addError('Demo-Product is occupied during the time frame specified!'); } } } } }

Here's how this works:

From a Demo record, Click the New Demo Rental button in the Demo Rental related list. The Demo field should be pre-populated for you. Enter a Demo Rental Name (alternatively, you could have set this up as an auto-number). Enter a Demo Product, and the Start & End Dates. Then click Save.

The trigger will search all 'Demo Rental' records that have the same product and return an error if the dates match specific criteria. If the dates are not in this range, the record will be saved.

Of course, there are other solutions out there... Hope this gets you started!

forawormforaworm

Thanks it helps getting started. But I have a further questions to it.

 

My post was referred to a test application. In fact I have an object named Trial (equals to Demo) and an object named Trial_Product (equals to Demo-Product). As well there exists an object named Trial_Connect (this would be equal to your Demo Rentals). It is already related to Trial and Trial_Product via lookup fields.

 

The real issue is a little more complicated. Trial_Connect is having only the two lookup fields. The date fields are on the Trial object.

 

I tried testing triggers step by step but I do not understand the whole codesnippet.

 

This is my codesnippet:

 

 

trigger checkTrialProductAvailable on Trial_Connect__c (before insert,before update) {

Set<ID> TrialProductIDs = new Set<ID>{};
Set<ID> TrialIDs = new Set<ID>{};
for(Trial_Connect__c objTrial_Connect : Trigger.new){
if(objTrial_Connect.Trial_Product__c != null){
TrialProductIDs.add(objTrial_Connect.Trial_Product__c);
TrialIDs.add(objTrial_Connect.Trial__c);
}
}

if(TrialProductIDs.size() > 0){
Map<ID,Trial_Connect__c> mapTrial_ConnectFields = new Map<ID,Trial_Connect__c>([
Select Id, Trial__c, Trial_Product__c
From Trial_Connect__c Where Trial_Product__c in:TrialProductIDs]);

// To display the map
Trial_Connect__c objTrial_Connect2 = trigger.new[0];
objTrial_Connect2.addError(mapTrial_ConnectFields);
}
}

 

 This is a result for the map:

 

{
a0YS0000000HGWQMA4=Trial_Connect__c:{Trial_Product__c=a0XS00000005APDMA2, Trial__c=a06S0000001IsDJIA0, Id=a0YS0000000HGWQMA4},
a0YS0000000HGWRMA4=Trial_Connect__c:{Trial_Product__c=a0XS00000005APDMA2, Trial__c=a06S0000001IsDSIA0, Id=a0YS0000000HGWRMA4},
a0YS0000000HGWVMA4=Trial_Connect__c:{Trial_Product__c=a0XS00000005APDMA2, Id=a0YS0000000HGWVMA4},
...}

 

It seems to be a map with:

 

KEY=a0YS0000000HGWQMA4 (ID of Trial_Connect I guess)

 

VALUE=Trial_Connect__c:{Trial_Product__c=a0XS00000005APDMA2,Trial__c=a06S0000001IsDJIA0,Id=a0YS0000000HGWQMA4}

 

VALUE will be done by statement "... Select Id, Trial__c, Trial_Product__c ...", but I do not understand how the KEY will be filled.

 

But my actually problem is how to read the value of Trial_c (Trial__c=a06S0000001IsDJIA0) to create another select to read the date fields.

 

Is VALUE Trial_Connect__c an object? To read the value of Trial__c with .getTrial__c() (as with java) does not work if I assign the VALUE from the map to an object. See codesnippet below.

  

Set<ID> mySet = new Set<ID>(mapTrial_ConnectFields.keySet());
Trial_Connect__c myTC;
Trials__c myT;

for(ID myID : mySet){
myTC = mapTrial_ConnectFields.get(myID);
myT = myTC.getTrial_Product__c();