Dynamic date in reports

Hi all,

We want to set up a report to run on a scheduled basis and provide all the provisioning transaction details from IIQ.

We have got the OOTB report “Provisioning Transaction Report“ but are trying to find a way to set the start and end date of the report to be taken dynamically every day as the last day and current day every time it runs.

How can we make this dynamic?

Thanks in advance

@rishavghoshacc You can modify the report or create a new report and add a query parameter with a queryScript which can set the date range. You can also introduce a report form where you can give options to select a period like yesterday, today, 7days, etc.

Please refer to doc, Page 110 for Report Forms and Page 114-115 to understand about query parameter.: 8.4 IdentityIQ Reports Guide - Compass

Note: Found a fix?Help the community by marking the comment as solution. Feel free to react(:heart:,:+1:, etc.)with an emoji to show your appreciation or message me directly if your problem requires a deeper dive.

@rishavghoshacc Try the value script available for parameter to set the date.

<Parameter>
      <ValueScript>
            <Source>
              **your code to set date**
             </Source>
       </ValueScript>
</Parameter>

@rishavghoshacc To get the start Date and endDate field dynamically based on your logic, you can modify the existing report or clone the same report and write the queryScript to set the date range.

Hi @rishavghoshacc ,

You can use the following report to get the provisioning transactions and customize according to your requirements.

The following is a customized OOTB report to get the provisioning transactions in a day

Form :

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE Form PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<Form  hidden="true" name="Custom Provisioning Transaction Report Form" type="Report">
  <Section columns="2" label="report_provisioning_transaction_form" name="customProperties">
    <Field displayName="report_provisioning_application" helpKey="help_report_provisioning_application" multi="true" name="applications" type="ProvisioningTransaction" value="ref:applications">
      <Attributes>
        <Map>
          <entry key="objectColumn" value="applicationName"/>
        </Map>
      </Attributes>
    </Field>
    <Field displayName="report_provisioning_identity" helpKey="help_report_provisioning_identity" multi="true" name="identities" type="Identity" value="ref:identities">
      <Attributes>
        <Map>
          <entry key="valueProperty" value="name"/>
        </Map>
      </Attributes>
    </Field>
    <Field displayName="report_provisioning_integration" helpKey="help_report_provisioning_integration" multi="true" name="integration" type="ProvisioningTransaction" value="ref:integration">
      <Attributes>
        <Map>
          <entry key="objectColumn" value="integration"/>
        </Map>
      </Attributes>
    </Field>
    <Field displayName="report_provisioning_native_identity" helpKey="help_report_provisioning_account_display_name" name="accountDisplayName" type="string" value="ref:accountDisplayName"/>
    <Field displayName="report_provisioning_operation" helpKey="help_report_provisioning_operation" multi="true" name="operation" type="string" value="ref:operation">
      <AllowedValuesDefinition>
        <Script>
          <Source>
                String[] operations = {
                    "Create",
                    "Delete",
                    "Disable",
                    "Enable",
                    "Lock",
                    "Modify",
                    "Unlock"
                };

                List values = new ArrayList();
                for (String operation : operations) {
                    List value = new ArrayList();
                    value.add(operation);
                    value.add(operation);

                    values.add(value);
                }

                return values;
              </Source>
        </Script>
      </AllowedValuesDefinition>
    </Field>
    <Field displayName="report_provisioning_source" helpKey="help_report_provisioning_source" multi="true" name="source" type="string" value="ref:source">
      <AllowedValuesDefinition>
        <Script>
          <Source>
                String[] sources = {
                    "Batch",
                    "Certification",
                    "GroupManagement",
                    "IdentityRefresh",
                    "LCM",
                    "PAM",
                    "PolicyViolation",
                    "RapidSetup",
                    "RoleChangePropagation",
                    "Rule",
                    "UI",
                    "Unknown",
                    "WebService",
                    "Workflow"
                };

                List values = new ArrayList();
                for (String source : sources) {
                    List value = new ArrayList();
                    value.add(source);
                    value.add(source);

                    values.add(value);
                }

                return values;
              </Source>
        </Script>
      </AllowedValuesDefinition>
    </Field>
    <Field displayName="report_provisioning_status" helpKey="help_report_provisioning_status" multi="true" name="status" type="string" value="ref:status">
      <AllowedValuesDefinition>
        <Script>
          <Source>
                      import sailpoint.object.*;
                      List enums = new ArrayList();
                      for(ProvisioningTransaction.Status enumItem : ProvisioningTransaction.Status.values()) {
                        List item = new ArrayList();
                        item.add(enumItem.toString());
                        item.add(enumItem.getLocalizedMessage());
                        enums.add(item);
                      }
                      return enums;
                  </Source>
        </Script>
      </AllowedValuesDefinition>
    </Field>
    <Field displayName="report_provisioning_type" helpKey="help_report_provisioning_type" multi="true" name="type" type="string" value="ref:type">
      <AllowedValuesDefinition>
        <Script>
          <Source>
                      import sailpoint.object.*;
                      List enums = new ArrayList();
                      for(ProvisioningTransaction.Type enumItem : ProvisioningTransaction.Type.values()) {
                        List item = new ArrayList();
                        item.add(enumItem.toString());
                        item.add(enumItem.getLocalizedMessage());
                        enums.add(item);
                      }
                      return enums;
                  </Source>
        </Script>
      </AllowedValuesDefinition>
    </Field>
    <Field columnSpan="1" displayName="report_provisioning_forced" helpKey="help_report_provisioning_forced" name="forced" type="boolean" value="ref:forced"/>
  </Section>
</Form>

TaskDefnition :

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE TaskDefinition PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<TaskDefinition  executor="sailpoint.reporting.LiveReportExecutor" name="Custom Provisioning Transaction Object Report" progressMode="Percentage" resultAction="Rename" subType="Administration Reports" template="true" type="LiveReport">
  <Attributes>
    <Map>
      <entry key="TaskDefinition.runLengthAverage" value="4"/>
      <entry key="TaskDefinition.runLengthTotal" value="4"/>
      <entry key="TaskDefinition.runs" value="1"/>
      <entry key="report">
        <value>
          <LiveReport title="Provisioning Transaction Object Report">
            <DataSource objectType="ProvisioningTransaction" type="Filter">
              <OptionsScript>
                <Source>
                  import org.apache.log4j.Logger;

                  import sailpoint.object.QueryOptions;
                  import sailpoint.object.Filter;

                  import java.util.Date;
                  import java.time.LocalDate;
                  import java.time.ZoneId;
                  import java.time.ZonedDateTime;

                  if(options!=null){

                  ZonedDateTime startdate = ZonedDateTime.now();

                  ZonedDateTime today = startdate.minusDays(0).withHour(0).withMinute(0).withSecond(0).withNano(0); 

                  Date endDate = Date.from(today.toInstant());

                  Date startDate = Date.from(startdate.toInstant());

                  Filter filter1 = Filter.ge("created",endDate);

                  Filter filter2 = Filter.le("created",startDate);

                  options.addFilter(filter1);
                  options.addFilter(filter2);


                  }

                  return options;
                </Source>
              </OptionsScript>
              <QueryParameters>
                <Parameter argument="identities" property="identityName"/>
                <Parameter argument="applications" property="applicationName"/>
                <Parameter argument="integration" property="integration">
                  <QueryScript>
                    <Source>

                      import sailpoint.object.*;
                      import java.util.*;

                      if (value != null &amp;&amp; !value.isEmpty()){
                      queryOptions.addFilter(Filter.ignoreCase(Filter.like("integration", value, Filter.MatchMode.START)));
                      }

                      return queryOptions;

                    </Source>
                  </QueryScript>
                </Parameter>
                <Parameter argument="accountDisplayName" property="accountDisplayName">
                  <QueryScript>
                    <Source>

                      import sailpoint.object.*;
                      import java.util.*;

                      if (value != null &amp;&amp; !value.isEmpty()){
                      queryOptions.addFilter(Filter.ignoreCase(Filter.like("accountDisplayName", value, Filter.MatchMode.START)));
                      }

                      return queryOptions;

                    </Source>
                  </QueryScript>
                </Parameter>
                <Parameter argument="status" property="status"/>
                <Parameter argument="type" property="type"/>
                <Parameter argument="operation" property="operation"/>
                <Parameter argument="source" property="source"/>
                <Parameter argument="creationDate" property="created" valueClass="daterange"/>
                <Parameter argument="forced" property="forced">
                  <QueryScript>
                    <Source>

                      import sailpoint.object.*;
                      import java.util.*;

                      if (value == true){
                      queryOptions.addFilter(Filter.eq("forced", true));
                      }

                      return queryOptions;

                    </Source>
                  </QueryScript>
                </Parameter>
              </QueryParameters>
            </DataSource>
            <ReportForm>
              <Reference class="sailpoint.object.Form" id="0a00020f9d381887819d3820f5cb0014" name="Custom Provisioning Transaction Report Form"/>
            </ReportForm>
            <Columns>
              <ReportColumnConfig field="name" header="report_provisioning_id" property="name" sortable="true" width="110">
                <RenderScript>
                  <Source>

                    import sailpoint.tools.Util;
                    return Util.stripLeadingChar(value, '0');

                  </Source>
                </RenderScript>
              </ReportColumnConfig>
              <ReportColumnConfig field="applicationName" header="report_provisioning_application" property="applicationName" sortable="true" width="110"/>
              <ReportColumnConfig field="identityDisplayName" header="report_provisioning_identity_display" property="identityDisplayName" sortable="true" width="110"/>
              <ReportColumnConfig field="identityName" header="report_provisioning_identity" property="identityName" sortable="true" width="110"/>
              <ReportColumnConfig field="integration" header="report_provisioning_integration" property="integration" sortable="true" width="110"/>
              <ReportColumnConfig field="nativeIdentity" header="report_provisioning_native_identity" property="nativeIdentity" sortable="true" width="110"/>
              <ReportColumnConfig field="accountDisplayName" header="report_provisioning_account_display" property="accountDisplayName" sortable="true" width="110"/>
              <ReportColumnConfig field="status" header="report_provisioning_status" property="status" sortable="true" width="110"/>
              <ReportColumnConfig field="type" header="report_provisioning_type" property="type" sortable="true" width="110"/>
              <ReportColumnConfig field="operation" header="report_provisioning_operation" property="operation" sortable="true" width="110"/>
              <ReportColumnConfig field="source" header="report_provisioning_source" property="source" sortable="true" width="110"/>
              <ReportColumnConfig field="created" header="report_provisioning_date" property="created" sortable="true" width="110"/>
              <ReportColumnConfig field="forced" header="report_provisioning_forced" property="forced" sortable="true" width="110"/>
            </Columns>
          </LiveReport>
        </value>
      </entry>
    </Map>
  </Attributes>
  <Description>Displays provisioning transactions.</Description>
  <RequiredRights>
    <Reference class="sailpoint.object.SPRight"  name="FullAccessProvisioningTransactionReport"/>
  </RequiredRights>
  <Signature>
    <Inputs>
      <Argument multi="true" name="applications" type="Application">
        <Description>help_report_provisioning_application</Description>
      </Argument>
      <Argument multi="true" name="identities" type="Identity">
        <Description>help_report_provisioning_identity</Description>
      </Argument>
      <Argument name="integration" type="string">
        <Description>help_report_provisioning_integration</Description>
      </Argument>
      <Argument name="accountDisplayName" type="string">
        <Description>help_report_provisioning_account_display_name</Description>
      </Argument>
      <Argument name="operation" type="string">
        <Description>help_report_provisioning_operation</Description>
      </Argument>
      <Argument name="source" type="string">
        <Description>help_report_provisioning_source</Description>
      </Argument>
      <Argument name="status" type="string">
        <Description>help_report_provisioning_status</Description>
      </Argument>
      <Argument name="type" type="string">
        <Description>help_report_provisioning_type</Description>
      </Argument>
      <Argument name="creationDate" type="date">
        <Description>help_report_provisioning_date</Description>
      </Argument>
      <Argument name="forced" type="boolean">
        <Description>help_report_provisioning_forced</Description>
      </Argument>
    </Inputs>
  </Signature>
</TaskDefinition>

I would recommend this approach. Thank you.

Hi @rishavghoshacc ,

Schedule the above report to run the report daily to get the provisioning transactions occured within a day.

@rishavghoshacc Have you tried the provided code samples and documents? Please let us know if you need any further help.

@Chathuryas How would I get the message for the transaction in the report. I need this for any failed transaction

Hi @rishavghoshacc ,

you can use the RenderScript to get the error message from the ProvsioningTransaction Object

@Chathuryas Can you please help me with the code. I am getting an error while doing this

Hi @rishavghoshacc ,

Append the following code to the above report to get the error messages of failed provisioning transactions.

 <ReportColumnConfig field="errorMsg" header="Error Message" property="attributes.accessRequestId" sortable="true" width="110">
                <RenderScript>
                  <Source>

                    import sailpoint.object.IdentityRequest;
                    import sailpoint.object.ProvisioningResult;
                    import sailpoint.tools.Util;
                    import sailpoint.tools.Message;
                    import sailpoint.tools.Message.Type;

                    String errorMessage = "";

                    if(value!=null){

                    IdentityRequest identityRequest = context.getObjectByName(IdentityRequest.class,value);

                    if(identityRequest!=null){

                    List messages = identityRequest.getMessagesByType(Message.Type.Error);
                    
                    if(messages!=null &amp;&amp; !messages.isEmpty()){

                    for(Message message : messages){

                    errorMessage = errorMessage + " " +  message.toString();

                    }

                    }

                    }


                    }

                    return errorMessage;
                  </Source>
                </RenderScript>
				
				</ReportColumnConfig

@Chathuryas This does not return any message for the failed transaction

Hi @rishavghoshacc ,

Can you check if the corresponding provisioning transaction objects has any message from the debug page. This code returns the message only if there is any message in the corresponding ProvisioningTransaction object and has a accessRequestId

@Chathuryas The objects does not have a accessReqeustId

<?xml version='1.0' encoding='UTF-8'?>
<!DOCTYPE ProvisioningTransaction PUBLIC "sailpoint.dtd" "sailpoint.dtd">
<ProvisioningTransaction applicationName="AD-Direct" created="1xxxx88" id="0xxxxc" identityDisplayName="Vxxxxi" identityName="Vxxxxx" integration="AD-Direct" modified="171xxxx8" name="00xxxx23" operation="Modify" source="RoleChangePropagation" status="Failed" type="Auto">
  <Attributes>
    <Map>
      <entry key="request">
        <value>
          <AccountRequest application="AD-Direct" op="Modify">
            <Attributes>
              <Map>
                <entry key="provisioningTransactionId" value="0a99xxxx559c"/>
              </Map>
            </Attributes>
            <AttributeRequest name="memberOf" op="Add" value="CN=DL_ xxxx,OU=Groups,OU=xxxx,OU=xxxx,OU=Bxxxxxx,DC=local"/>
            <ProvisioningResult status="failed">
              <Errors>
                <Message key="Native Identity should not be null or empty" type="Error"/>
              </Errors>
            </ProvisioningResult>
          </AccountRequest>
        </value>
      </entry>
    </Map>
  </Attributes>
</ProvisioningTransaction>

@rishavghoshacc Not every transaction is associated with access request. to print the message, read it from ProvisioningResult. Could you please share your current report which you have developed, will update and send you back.

@rishavghoshacc , I have tried without the using the accessRequestId but the ProvisioningResult is always returning as null even though the ProvisioningResult existed in the ProvisioningTransaction hence I suggested this approach.

@neel193

Custom Provisioning Transaction Object Report.xml (9.6 KB)

@rishavghoshacc Please add a column and renderscript like below:

 <ReportColumnConfig field="errorMsg" header="ErrorMessage" property="attributes.request" sortable="true" width="110">
                <RenderScript>
                  <Source>
                return value.getResult().getErrors().toString();
                  </Source>
                </RenderScript>
              </ReportColumnConfig>

Please add a null check in script, so it should not fail in case there is no result or no error. See the attached email how it’ll look like.

Note: Found a fix?Help the community by marking the comment as solution. Feel free to react(:heart:,:+1:, etc.)with an emoji to show your appreciation or message me directly if your problem requires a deeper dive.

@neel193 The screenshot of the ProvisioningTransaction you have shared has accessRequest. So, it will return the error message, The issue is if the provisioningTransaction does not have a identityRequest Id , then while using request in attributes and returning result, the result is always returning as null even though it exists in the ProvisioningTransaction object in debug page.

value.getResult(); // This is returning as null if the ProvisioningTransaction does not have accessRequestid , even if we use null check, it will not enter the block as it is returning null hence it is not possible to get error message without accessRequestId.

 <ReportColumnConfig field="errorMsg" header="Error Message" property="attributes.request" sortable="true" width="110">
                <RenderScript>
                  <Source>  import sailpoint.object.ProvisioningPlan.AccountRequest;
                import sailpoint.object.ProvisioningResult;
                import sailpoint.tools.Util;
                import sailpoint.tools.Message;

                String errorMessage = "";

                if(value!=null &amp;&amp; value instanceof AccountRequest){

                AccountRequest accReq = (AccountRequest) value;

                ProvisioningResult result = accReq.getResult();

                if(result!=null ){

                List messages = result.getErrors();

                if(messages!=null &amp;&amp; !messages.isEmpty()){

                for(Message message : messages){

                errorMessage = errorMessage + " " +  message.toString();

                }

                }


                }


                }

                return errorMessage;

              </Source>
            </RenderScript>
          </ReportColumnConfig>