• Share
    • Twitter
    • LinkedIn
    • Facebook
    • Email
  • Feedback
  • Edit
Show / Hide Table of Contents

How to Search using Find Selections

•
Environment: online, onsite
•
Version: 9.2
Some tooltip text!
• 25 minutes to read
 • 25 minutes to read
Note

The API details provided apply to SuperOffice v.9.2 and higher. Find searches do not yet support custom entities or extra tables. SOAP API access via the Services88 endpoints, therefore online Apps must request Services88 to use this API.

The first thing to understand is that search is based on a selection. However, a search doesn’t explicitly require a preexisting selection to perform a search. Using the API the same way the SuperOffice Find dialog works, implicitly creates a selection on a per-associate per-entity basis.

Steps

The steps used to perform a search are:

  1. Get the list of available search entities.
  2. Determine which entity to base the search such as company, contact, sale, project, and so on.
  3. Get the data source used to perform the search, the name of a dynamic selection archive provider.
  4. Get the available data source columns, for specifying return fields and criteria.
  5. Set the search criteria.
  6. Perform the search.
  7. Read the results.

Get the search entities

The Find page dynamically displays all entities that support the new Find system.

Find Dialog

Note

Your Find options may not be the same as shown. Available entities depend on the current user's license.

To determine which entities are available, use the MDO endpoint to get a list of available entities using the SelectionMemberTypeV2 MDOList provider.

  • REST
  • Agent
  • WebApi Client
GET /api/v1/MDOList/SelectionMemberTypeV2
Authorization: Bearer {access_token}
Content-Type: application/json
Accept: application/json
POST /api/v1/Agents/MDO/GetList
Authorization: Bearer {access_token}
Accept: application/json; charset=utf-8
Accept-Language: en
Content-Type: application/json; charset=utf-8
{
  "Name": "selectionmembertypev2",
  "ForceFlatList": true,
  "AdditionalInfo": "",
  "OnlyHistory": false
}
// setup access credentials
var authorization = new AuthorizationAccessToken("{access_token}", OnlineEnvironment.SOD);
var options = new WebApiOptions("https://sod.superoffice.com/Cust12345/api", authorization);

// perform the request
var mdoAgent = new MDOAgent(options);
MDOListItem[] findEntities = await mdoAgent.GetListAsync("selectionmembertypev2", true, string.Empty, false);

The result is an array of MDOListItem and contains the following details. Use the name of the ExtraInfo property to define the search entity.

Results (some properties omitted for brevity)

Id Name IconHint ExtraInfo
1 [SR_FIND_COMPANY] Contact contact
2 [SR_FIND_PERSON] Person person
3 [SR_FIND_APPOINTMENT] Appointment appointment
4 [SR_FIND_SALE] Sale sale
5 [SR_FIND_PROJECT] Project project
6 [SR_FIND_SELECTION] Selection selection
7 [SR_FIND_DOCUMENT] Document document
8 [SR_FIND_QUOTELINE] Products QuoteLine
9 [SR_FIND_TICKET] Ticket ticket
Note

Use header options to specify an Accept-Language to replace the resource strings with localized labels.

Get the entity data source

You need 2 key pieces of information to get the data source, the archive provider and the selection ID. These are both available in a SelectionForFind instance. Use the ExtraInfo value from the previous results to get a SelectionForFind instance.

Use the SelectionAgent.GetSelectionForFind(entityName, typicalSearchId) method to obtain the SelectionForFind type for a particular entity.

The value of typicalSearchId determines some internal logic.

TypicalSearchID Description
-1 Gets the default criteria for the current entity, and the selectionId of the working set is returned along with the providerName.
0 Gets the working set and doesn’t do anything else.
1 or higher Gets a selection with criteria set from the typical search of the given ID.
  • HTTP RPC Agent
  • WebApi Client
POST /api/v1/Agents/Selection/GetSelectionForFind 
Authorization: Bearer {{token}}
Content-Type: application/json
Accept: application/json

{
  "EntityName": "contact",
  "TypicalSearchId": 0
}
// setup access credentials
var authorization = new AuthorizationAccessToken("{access_token}", OnlineEnvironment.SOD);
var options = new WebApiOptions("https://sod.superoffice.com/Cust12345/api", authorization);

// perform the request
var selectionAgent = new SelectionAgent(options);

var entityName = "contact";
var typicalSearchId = 0;

SelectionForFind selectionForFind = await selectionAgent.GetSelectionForFind(entityName, typicalSearchId);

SelectionForFind properties

Property Description
CanSaveAsSelection Indicates of selection entity can be saved as a selection.
FieldProperties Mapping field names to access rights.
FilterScreenHeading Heading used on the Find filter page in SuperOffice.
MainHeading Heading used on the Find front page in SuperOffice.
ProviderName The name of the main archive provider use with this selection entity type.
SelectionEntityHeading The plural form of the entity name, used on the Selection Details tab.
SelectionId The selections primary key.
TableRight The carrier table rights.

The ProviderName property is the name of the archive provider used to search. In this example, when contact is used as the entity name, the results return ContactPersonDynamicSelectionV2 as the archive provider name.

The SelectionId indicates the selection's primary key for this associate/entity pair. The selection has a default list of criteria used to pre-populate a new selection of this entity type.

SelectionForFind result

{
  "ProviderName": "ContactPersonDynamicSelectionV2",
  "SelectionId": 21,
  "CanSaveAsSelection": true,
  "MainHeading": "[SR_FIND_COMPANY]",
  "FilterScreenHeading": "[SR_FIND_COMPANY]",
  "SelectionEntityHeading": "[SR_COMPANY_AND_PERSON]",
  "TableRight": null,
  "FieldProperties": {}
}
Note

The selection ID used here does not appear as an available Selection in SuperOffice. It's only used for Find purposes.

Provider names

All dynamic Find Selections use an archive provider whose name ends with the V2 suffix. However, when using the Find API, do not rely on this list, instead use the API as shown to ensure you always get the correct provider.

  • AppointmentDynamicSelectionV2
  • ContactPersonDynamicSelectionV2
  • DocumentDynamicSelectionV2
  • ProjectDynamicSelectionV2
  • QuotelineDynamicSelectionV2
  • SaleDynamicSelectionV2
  • SelectionDynamicSelectionV2
  • TicketDynamicSelectionV2

These providers are exclusively used together with the new CriteriaGroups for specifying restrictions. Retrieve the SelectionForFind type, then use the provider name and selection ID to set the desired search criteria.

Get the search columns

Search columns are used to define what field to select and specify the criteria for limiting the result set.

Tip

Because these never change at runtime, make sure to use caching when able.

Selection criteria

Just like a SQL SELECT statement, where there are any number of select fields and any number of WHERE clause criteria, selections use archive provider columns to determine select and criteria fields. A selection criterion is set using CriteriaGroups.

One CriteriaGroup is an ArchiveRestrictionGroup and contains an array of ArchiveRestrictionInfo, and each ArchiveRestrictionInfo is implicitly joined by an AND operator.

CriteriaGroup

Take the following SQL, for example:

SELECT firstName, lastName 
FROM CONTACT AS C
WHERE (C.name LIKE 'Super%' AND C.business_idx = 2) 
   OR (C.name LIKE 'Duper%' AND C.category_idx = 12)

The first WHERE criteria (C.name LIKE 'Super%' AND C.business_idx = 2) is a criteria group, comprised of 2 distinct criteria. To build the equivalent into an ArchiveRestrictionGroup, it looks like this:

var criteriaGroup = new ArchiveRestrictionGroup()
{
    Name = "0",
    Rank = 0,
    Description = "Hidden Description",
    Restrictions = new []
    {
        new ArchiveRestrictionInfo()
        {
            Name = "name",
            Operator = "begins",
            Values = new[] { "Super" },
            IsActive = true,
            ColumnInfo = new ArchiveColumnInfo()
            {
                Name = "name",
                RestrictionType = "stringorPK",
                RestrictionListName = "locateContact_new",
                //... left out for brevity
            },
            InterOperator = InterRestrictionOperator.And
        },
        new ArchiveRestrictionInfo()
        {
            Name = "name",
            Operator = "begins",
            Values = new[] { "Duper" },
            IsActive = true,
            ColumnInfo = new ArchiveColumnInfo()
            {
                Name = "name",
                RestrictionType = "stringorPK",
                RestrictionListName = "locateContact_new",
                //... left out for brevity
            },
            InterOperator = InterRestrictionOperator.And
        }
    }
};

CriteriaGroups is an array of ArchiveRestrictionGroup, and each group is implicitly joined by an OR operator.

As seen in the example above, the Name and Rank share the same numerical value, represent the order they appear in SuperOffice. The Name and Rank for the next ArchiveRestrictionGroup in the array is 1, and any subsequent group would increment accordingly.

Archive columns

To specify a field restriction you first need to get an ArchiveColumnInfo instance. While it's possible to lookup archive provider columns using the NetServer documentation reference, it's recommended to get and cache the columns using the API. This is required to set the required information in an ArchiveRestrictionInfo.

Get archive provider columns

  • HTTP RPC Agent
  • WebApi Client
POST /api/v1/Agents/Archive/GetAvailableColumns
Authorization: Bearer {{token}}
Accept: application/json; charset=utf-8
Accept-Language: en
Content-Type: application/json; charset=utf-8

{
  "ProviderName": "ContactPersonDynamicSelectionV2",
  "Context": ""
}
// setup access credentials
var authorization = new AuthorizationAccessToken("{access_token}", OnlineEnvironment.SOD);
var options = new WebApiOptions("https://sod.superoffice.com/Cust12345/api", authorization);

// perform the request
var archiveAgent = new ArchiveAgent(options);
var providerName = "ContactPersonDynamicSelectionV2";
ArchiveColumnInfo[] availableColumns = await archiveAgent.GetAvailableColumns(providerName, "");

Get archive provider column results

[
  {
    "DisplayName": "Selection ID",
    "DisplayTooltip": "The database ID of the selection",
    "DisplayType": "int",
    "CanOrderBy": false,
    "Name": "selectionId",
    "CanRestrictBy": true,
    "RestrictionType": "int",
    "RestrictionListName": null,
    "IsVisible": false,
    "ExtraInfo": "",
    "Width": "8c",
    "IconHint": "",
    "HeadingIconHint": ""
  },
  {
    "DisplayName": "Company ID",
    "DisplayTooltip": "Database ID of company",
    "DisplayType": "int",
    "CanOrderBy": true,
    "Name": "contactId",
    "CanRestrictBy": true,
    "RestrictionType": "int",
    "RestrictionListName": null,
    "IsVisible": true,
    "ExtraInfo": "",
    "Width": "5c",
    "IconHint": "Contact",
    "HeadingIconHint": ""
  },
  {
    "DisplayName": "Company name",
    "DisplayTooltip": "",
    "DisplayType": "string",
    "CanOrderBy": true,
    "Name": "name",
    "CanRestrictBy": true,
    "RestrictionType": "stringorPK",
    "RestrictionListName": "locateContact_new",
    "IsVisible": true,
    "ExtraInfo": "",
    "Width": "25%",
    "IconHint": "Contact",
    "HeadingIconHint": ""
  },
  {
    "DisplayName": "Department",
    "DisplayTooltip": "",
    "DisplayType": "string",
    "CanOrderBy": true,
    "Name": "department",
    "CanRestrictBy": true,
    "RestrictionType": "string",
    "RestrictionListName": null,
    "IsVisible": true,
    "ExtraInfo": "",
    "Width": "25%",
    "IconHint": "Contact",
    "HeadingIconHint": ""
  },
  {
    "DisplayName": "Company",
    "DisplayTooltip": "Displays the company an activity is linked to",
    "DisplayType": "string",
    "CanOrderBy": true,
    "Name": "nameDepartment",
    "CanRestrictBy": false,
    "RestrictionType": null,
    "RestrictionListName": null,
    "IsVisible": true,
    "ExtraInfo": "",
    "Width": "25%",
    "IconHint": "Contact",
    "HeadingIconHint": ""
  },
  {
    "DisplayName": "Has note",
    "DisplayTooltip": "Displays an icon indicating if there is additional information available about the contact",
    "DisplayType": "icon",
    "CanOrderBy": true,
    "Name": "hasInfoText",
    "CanRestrictBy": true,
    "RestrictionType": "bool",
    "RestrictionListName": null,
    "IsVisible": true,
    "ExtraInfo": "",
    "Width": "2c",
    "IconHint": "Contact",
    "HeadingIconHint": "paperclip"
  },
  //... removed for brevity
]

Important ArchiveColumnInfo properties

Property Description
CanOrderBy Determines whether this column be used for sorting.
CanRestrictBy Determines whether this column be used as a restriction.
Name Unique identity of this column; the name to be used when requesting the column from a provider, setting restrictions or order by criteria.
RestrictionType The data type of the restriction; use this to retrieve the legal operators for the restriction.
RestrictionListName If the restriction data type is list, this property contains the name of the SoList so that choices can be shown.
IconHint Used to group with corresponding columns.

Get field operators by data type

A field operator determines what type of operation the criteria performs, such as comparison or range. Use the RestrictionType property to get the available operators for a given data type.

Restriction type Is list type
bool No
date No
datetime No
decimal No
int No
positiveString No
string No
stringorPK No
associate Yes
ejUser Yes
intArray Yes
listAll Yes
listAny Yes
listInterest Yes
userGroup Yes
  • REST
  • Agent
  • WebApi Client
GET /api/v1/MDOList/restrictionOperators/selectable?additional=positiveString 
Authorization: Bearer {{token}}
Content-Type: application/json
Accept: application/json
Accept-Language: en

POST /api/v1/Agents/MDO/GetList 
Authorization: Bearer {{token}}
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=utf-8
Accept-Language: en

{
  "Name": "restrictionOperators",
  "ForceFlatList": true,
  "AdditionalInfo": "positiveString",
  "OnlyHistory": false
}

// setup access credentials
var authorization = new AuthorizationAccessToken("{access_token}", OnlineEnvironment.SOD);
var options = new WebApiOptions("https://sod.superoffice.com/Cust12345/api", authorization);
// set Language options to en

// perform the request
var mdoAgent = new MDOAgent(options);
MDOListItem[] listItems = await mdoAgent.GetList("restrictionOperators","true","positiveString",false);

REST JSON results

[
  {
    "Id": 1,
    "Name": "Starts with",
    "ToolTip": "",
    "Deleted": false,
    "Rank": 1,
    "Type": "begins",
    "ColorBlock": 0,
    "IconHint": "",
    "Selected": false,
    "LastChanged": "0001-01-01T00:00:00",
    "ChildItems": [],
    "ExtraInfo": "W",
    "StyleHint": "",
    "Hidden": false,
    "FullName": null,
    "TableRight": null,
    "FieldProperties": {}
  },
  {
    "Id": 2,
    "Name": "Contains",
    "ToolTip": "",
    "Deleted": false,
    "Rank": 2,
    "Type": "contains",
    "ColorBlock": 0,
    "IconHint": "",
    "Selected": false,
    "LastChanged": "0001-01-01T00:00:00",
    "ChildItems": [],
    "ExtraInfo": "W",
    "StyleHint": "",
    "Hidden": false,
    "FullName": null,
    "TableRight": null,
    "FieldProperties": {}
  },
  {
    "Id": 3,
    "Name": "Ends with",
    "ToolTip": "",
    "Deleted": false,
    "Rank": 3,
    "Type": "ends",
    "ColorBlock": 0,
    "IconHint": "",
    "Selected": false,
    "LastChanged": "0001-01-01T00:00:00",
    "ChildItems": [],
    "ExtraInfo": "W",
    "StyleHint": "",
    "Hidden": false,
    "FullName": null,
    "TableRight": null,
    "FieldProperties": {}
  },
  {
    "Id": 4,
    "Name": "Equals",
    "ToolTip": "",
    "Deleted": false,
    "Rank": 4,
    "Type": "is",
    "ColorBlock": 0,
    "IconHint": "",
    "Selected": false,
    "LastChanged": "0001-01-01T00:00:00",
    "ChildItems": [],
    "ExtraInfo": "W",
    "StyleHint": "",
    "Hidden": false,
    "FullName": null,
    "TableRight": null,
    "FieldProperties": {}
  }
]

Use the Type property to specify the ArchiveRestrictionInfo Operator property.

Example: Working with columns and operators (WebApi client)

private async void ColumnInfoArchiveRestrictionInfoAsync(Tenant tenant)
{
  // not important for the sake of this example
  var config = GetWebApiConfiguration(tenant); 

  var archiveAgent = new ArchiveAgent(config);
  var mdoAgent = new MDOAgent(config);

  // get available entities and columns (cache these in production!)

  MDOListItem[] entities = await archiveAgent.GetAvailableEntitiesAsync("ContactPersonDynamicSelectionV2", "");
  ArchiveColumnInfo[] columns = await archiveAgent.GetAvailableColumnsAsync("ContactPersonDynamicSelectionV2", "");

  // get companyId field

  ArchiveColumnInfo companyIdColumn = columns
      .Where(c => c.Name.Equals("contactId", StringComparison.OrdinalIgnoreCase))
      .Select(c => c).First(); // throw if not found

  // get all operators for the companyId column data type (cache these in production)

  MDOListItem[] operators = await mdoAgent.GetListAsync(
      "restrictionOperators", 
      true, 
      companyIdColumn.RestrictionType,
      false);

  // get just the equals operator

  MDOListItem equalsOperator = operators
      .Where(o => o.Name.Equals("Equals", StringComparison.OrdinalIgnoreCase))
      .Select(o => o).First(); // throw if not found

  // instantiate an ArchiveRestrictionInfo
  // set the ColumnInfo, set to active, and specify the criteria "contactId is 5"

  var restriction = new ArchiveRestrictionInfo()
  {
      ColumnInfo = companyIdColumn,
      IsActive = true,
      Name = companyIdColumn.Name,
      Operator = equalsOperator.Type, // "is"
      Values = new[] { "5" }
  };
}

Set search criteria

Fetching and saving criteria

The new search routines introduce the concept of criteria groups, where all criteria in a group are connected by AND operators, and all groups in the array of CriteriaGroups are connected by OR operators.

Selection CriteriaGroups

The main points to understand are:

  1. Each ArchiveRestrictionInfo in an ArchiveRestrictionGroup is implicitly joined by an AND operator.
  2. Each ArchiveRestrictionGroup is implicitly joined by an OR operator.

The grouping and use of the AND and OR operators as such means it’s simple to define, maintain and comprehend how groups of criteria are applied to search routines.

The database layout to support this has been in place for a long time and was used in an equivalent fashion for Saint Status definitions. There, each criteria group was in a separate tab in the user interface; in the new Find screen, criteria groups are instead stacked vertically.

Selection CriteriaGroups

Selection criteria are fetched and stored using the GetDynamicSelectionCriteriaGroups and SetDynamicSelectionCriteriaGroups methods on the Selection agent. Using them will retrieve and save all groups, and avoid having to make assumptions about the StorageKey concept used in the Find agent methods.

This example demonstrates how to get existing CriteriaGroups for a given selection.

  • REST
  • Agent
  • WebApi Client
GET /api/v1/Selection/28/CriteriaGroups
Authorization: Bearer {{token}}
Content-Type: application/json
Accept: application/json
Accept-Language: en
POST /api/v1/Agents/Selection/GetDynamicSelectionCriteriaGroups
Authorization: Bearer {{token}}
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=utf-8
Accept-Language: en

{
  "SelectionId": 28
}
// setup access credentials
var authorization = new AuthorizationAccessToken("{access_token}", OnlineEnvironment.SOD);
var options = new WebApiOptions("https://sod.superoffice.com/Cust12345/api", authorization);
// set Language options to en

// perform the request
var selectionAgent = new SelectionAgent(options);
ArchiveRestrictionGroup[] criteriaGroups = await selectionAgent.GetDynamicSelectionCriteriaGroups(28);

The following example demonstrates how to set the criteria for the personalized person entity. The criteria say to return all persons where the first name starts with B and ends with Y, or the first name starts with R and ends with Y.

The SQL equivalent is:

SELECT fName, lName
FROM Person
WHERE (fName LIKE 'B%' AND lName LIKE 'Y%')
   OR (fName LIKE 'R%' AND lName LIKE 'Y%')

This code sets the criteria for the personalized selection equal to the SelectionForFind.SelectionId. The SetDynamicSelectionCriteriaGroups[Async] method returns the criteria groups that were passed in.

  • REST
  • Agent
  • WebApi Client
PUT /api/v1/Selection/24/CriteriaGroups
Authorization: Bearer {{token}}
Content-Type: application/json
Accept: application/json

[
  {
    "Name": "0",
    "Description": "",
    "Rank": 0,
    "Restrictions": [
      {
        "Name": "firstName",
        "Operator": "begins",
        "Values": [
          "B"
        ],
        "DisplayValues": [
          "B"
        ],
        "ColumnInfo": {
          "DisplayName": "[SR_PERSONARCHIVE_FIRSTNAME]",
          "DisplayTooltip": "[SR_PERSONARCHIVE_FIRSTNAME_TOOLTIP]",
          "DisplayType": "string",
          "CanOrderBy": true,
          "Name": "firstName",
          "CanRestrictBy": true,
          "RestrictionType": "string",
          "RestrictionListName": null,
          "IsVisible": true,
          "ExtraInfo": "",
          "Width": "20%",
          "IconHint": "Person",
          "HeadingIconHint": ""
        },
        "IsActive": true,
        "SubRestrictions": null,
        "InterParenthesis": 0,
        "InterOperator": "And",
        "UniqueHash": 939057318
      },
      {
        "Name": "lastName",
        "Operator": "begins",
        "Values": [
          "Y"
        ],
        "DisplayValues": [
          "Y"
        ],
        "ColumnInfo": {
          "DisplayName": "[SR_PERSONARCHIVE_LASTNAME]",
          "DisplayTooltip": "[SR_PERSONARCHIVE_LASTNAME_TOOLTIP]",
          "DisplayType": "string",
          "CanOrderBy": true,
          "Name": "lastName",
          "CanRestrictBy": true,
          "RestrictionType": "string",
          "RestrictionListName": null,
          "IsVisible": true,
          "ExtraInfo": "",
          "Width": "20%",
          "IconHint": "Person",
          "HeadingIconHint": ""
        },
        "IsActive": true,
        "SubRestrictions": null,
        "InterParenthesis": 0,
        "InterOperator": "And",
        "UniqueHash": -588059390
      }
    ]
  },
  {
    "Name": "1",
    "Description": "",
    "Rank": 1,
    "Restrictions": [
      {
        "Name": "firstName",
        "Operator": "begins",
        "Values": [
          "R"
        ],
        "DisplayValues": [
          "R"
        ],
        "ColumnInfo": {
          "DisplayName": "[SR_PERSONARCHIVE_FIRSTNAME]",
          "DisplayTooltip": "[SR_PERSONARCHIVE_FIRSTNAME_TOOLTIP]",
          "DisplayType": "string",
          "CanOrderBy": true,
          "Name": "firstName",
          "CanRestrictBy": true,
          "RestrictionType": "string",
          "RestrictionListName": null,
          "IsVisible": true,
          "ExtraInfo": "",
          "Width": "20%",
          "IconHint": "Person",
          "HeadingIconHint": ""
        },
        "IsActive": true,
        "SubRestrictions": null,
        "InterParenthesis": 0,
        "InterOperator": "And",
        "UniqueHash": 939057318
      },
      {
        "Name": "lastName",
        "Operator": "begins",
        "Values": [
          "Y"
        ],
        "DisplayValues": [
          "Y"
        ],
        "ColumnInfo": {
          "DisplayName": "[SR_PERSONARCHIVE_LASTNAME]",
          "DisplayTooltip": "[SR_PERSONARCHIVE_LASTNAME_TOOLTIP]",
          "DisplayType": "string",
          "CanOrderBy": true,
          "Name": "lastName",
          "CanRestrictBy": true,
          "RestrictionType": "string",
          "RestrictionListName": null,
          "IsVisible": true,
          "ExtraInfo": "",
          "Width": "20%",
          "IconHint": "Person",
          "HeadingIconHint": ""
        },
        "IsActive": true,
        "SubRestrictions": null,
        "InterParenthesis": 0,
        "InterOperator": "And",
        "UniqueHash": -588059390
      }
    ]
  }
]

POST /api/v1/Agents/Selection/SetDynamicSelectionCriteriaGroups
Authorization: Bearer {{token}}
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=utf-8
Accept-Language: en

{
  "SelectionId": 24,
  "Criteria": [
    {
      "Name": "0",
      "Description": "",
      "Rank": 0,
      "Restrictions": [
        {
          "Name": "firstName",
          "Operator": "begins",
          "Values": [
            "B"
          ],
          "DisplayValues": [
            "B"
          ],
          "ColumnInfo": {
            "DisplayName": "[SR_PERSONARCHIVE_FIRSTNAME]",
            "DisplayTooltip": "[SR_PERSONARCHIVE_FIRSTNAME_TOOLTIP]",
            "DisplayType": "string",
            "CanOrderBy": true,
            "Name": "firstName",
            "CanRestrictBy": true,
            "RestrictionType": "string",
            "RestrictionListName": null,
            "IsVisible": true,
            "ExtraInfo": "",
            "Width": "20%",
            "IconHint": "Person",
            "HeadingIconHint": ""
          },
          "IsActive": true,
          "SubRestrictions": null,
          "InterParenthesis": 0,
          "InterOperator": "And",
          "UniqueHash": 939057318
        },
        {
          "Name": "lastName",
          "Operator": "begins",
          "Values": [
            "Y"
          ],
          "DisplayValues": [
            "Y"
          ],
          "ColumnInfo": {
            "DisplayName": "[SR_PERSONARCHIVE_LASTNAME]",
            "DisplayTooltip": "[SR_PERSONARCHIVE_LASTNAME_TOOLTIP]",
            "DisplayType": "string",
            "CanOrderBy": true,
            "Name": "lastName",
            "CanRestrictBy": true,
            "RestrictionType": "string",
            "RestrictionListName": null,
            "IsVisible": true,
            "ExtraInfo": "",
            "Width": "20%",
            "IconHint": "Person",
            "HeadingIconHint": ""
          },
          "IsActive": true,
          "SubRestrictions": null,
          "InterParenthesis": 0,
          "InterOperator": "And",
          "UniqueHash": -588059390
        }
      ]
    },
    {
      "Name": "1",
      "Description": "",
      "Rank": 1,
      "Restrictions": [
        {
          "Name": "firstName",
          "Operator": "begins",
          "Values": [
            "R"
          ],
          "DisplayValues": [
            "R"
          ],
          "ColumnInfo": {
            "DisplayName": "[SR_PERSONARCHIVE_FIRSTNAME]",
            "DisplayTooltip": "[SR_PERSONARCHIVE_FIRSTNAME_TOOLTIP]",
            "DisplayType": "string",
            "CanOrderBy": true,
            "Name": "firstName",
            "CanRestrictBy": true,
            "RestrictionType": "string",
            "RestrictionListName": null,
            "IsVisible": true,
            "ExtraInfo": "",
            "Width": "20%",
            "IconHint": "Person",
            "HeadingIconHint": ""
          },
          "IsActive": true,
          "SubRestrictions": null,
          "InterParenthesis": 0,
          "InterOperator": "And",
          "UniqueHash": 939057318
        },
        {
          "Name": "lastName",
          "Operator": "begins",
          "Values": [
            "Y"
          ],
          "DisplayValues": [
            "Y"
          ],
          "ColumnInfo": {
            "DisplayName": "[SR_PERSONARCHIVE_LASTNAME]",
            "DisplayTooltip": "[SR_PERSONARCHIVE_LASTNAME_TOOLTIP]",
            "DisplayType": "string",
            "CanOrderBy": true,
            "Name": "lastName",
            "CanRestrictBy": true,
            "RestrictionType": "string",
            "RestrictionListName": null,
            "IsVisible": true,
            "ExtraInfo": "",
            "Width": "20%",
            "IconHint": "Person",
            "HeadingIconHint": ""
          },
          "IsActive": true,
          "SubRestrictions": null,
          "InterParenthesis": 0,
          "InterOperator": "And",
          "UniqueHash": -588059390
        }
      ]
    }
  ]
}
private async Task<ArchiveRestrictionGroup[]> SetPersonSearchCriteria(
    ArchiveAgent archiveAgent,
    SelectionAgent selectionAgent,
    MDOAgent mdoAgent,
    SelectionForFind selectionForFind)
{
    // get archive provider columns

    ArchiveColumnInfo[] columns = await archiveAgent.GetAvailableColumnsAsync(
        selectionForFind.ProviderName,
        "");

    // get just the first and last name columns

    var firstNameColumn = columns.Where(c => c.Name == "firstName").Select(c => c).FirstOrDefault();
    var lastNameColumn = columns.Where(c => c.Name == "lastName").Select(c => c).FirstOrDefault();

    // get operator from the column datatype
    // both firstName and lastName are the same data type...so only get one.

    MDOListItem[] operators = await mdoAgent.GetListAsync(
        "restrictionOperators",
        true,
        firstNameColumn.RestrictionType,
        false);

    // get the "begins" operator

    MDOListItem beginsOperator = operators
        .Where(o => o.Type.Equals("begins", StringComparison.OrdinalIgnoreCase))
        .Select(o => o).FirstOrDefault(); // throw if not found

    // define the criteria

    var criteriaGroups = new ArchiveRestrictionGroup[]
    {
        new ArchiveRestrictionGroup()
        {
             Name = "0",
             Rank = 0,
             Restrictions = new ArchiveRestrictionInfo[]
             {
                new ArchiveRestrictionInfo()
                {
                    Name = firstNameColumn.Name,
                    Operator = beginsOperator.Type,
                    Values = new[] {"B"},
                    IsActive = true,
                    ColumnInfo = firstNameColumn
                }, // AND
                new ArchiveRestrictionInfo()
                {
                    Name = lastNameColumn.Name,
                    Operator = beginsOperator.Type,
                    Values = new[] {"Y"},
                    IsActive = true,
                    ColumnInfo = lastNameColumn
                }
             }
        }, // OR
        new ArchiveRestrictionGroup()
        {
            Name = "1",
             Rank = 1,
             Restrictions = new ArchiveRestrictionInfo[]
             {
                new ArchiveRestrictionInfo()
                {
                    Name = firstNameColumn.Name,
                    Operator = beginsOperator.Type,
                    Values = new[] {"R"},
                    IsActive = true,
                    ColumnInfo = firstNameColumn
                }, // AND
                new ArchiveRestrictionInfo()
                {
                    Name = lastNameColumn.Name,
                    Operator = beginsOperator.Type,
                    Values = new[] {"Y"},
                    IsActive = true,
                    ColumnInfo = lastNameColumn
                }
             }
        }
    };

    // set the criteria

    return await selectionAgent.SetDynamicSelectionCriteriaGroupsAsync(
        selectionForFind.SelectionId,
        criteriaGroups);
}

Perform the search

The search is performed using the Archive endpoint, which facilitates passing common parameters, including:

  • Provider name
  • Desired columns
  • Sort order
  • Restriction
  • Entities
  • Page
  • Page size

The selectionId in these examples is obtained from the SelectionForFind.SelectionId property in previous snippets.

  • REST
  • HTTP RPC Agent
  • WebClient API
GET /api/v1/archive/ContactPersonDynamicSelectionV2?$select=firstName,lastName&$filter=selectionId = 34
Authorization: Bearer {{token}}
Content-Type: application/json
Accept: application/json
POST /api/v1/Agents/Archive/GetArchiveListByColumns
Authorization: Bearer {{token}}
Accept: application/json; charset=utf-8
Content-Type: application/json; charset=utf-8
Accept-Language: en

{
  "ProviderName": "ContactPersonDynamicSelectionV2",
  "Columns": [
    "firstName",
    "lastName"
  ],
  "SortOrder": [
    {
      "Name": "firstName",
      "Direction": "ASC"
    }
  ],
  "Restriction": [
    {
      "Name": "selectionId",
      "Operator": "=",
      "Values": [
        "34"
      ]
    }
  ],
  "Entities": [
    "person"
  ],
  "Page": 0,
  "PageSize": 100
}
string searchEntity = "person";
string[] columns = new[] { "firstName", "lastName" };

SelectionForFind selectionForFind = await selectionAgent
    .GetSelectionForFindAsync(searchEntity, 0);

ArchiveListItem[] results = await archiveAgent.GetArchiveListByColumnsAsync(
    selectionForFind.ProviderName,
    columns,
    new[]
    {
        new ArchiveOrderByInfo() 
        {
            Name = columns[0], 
            Direction = OrderBySortType.ASC 
        }
    },
    new[]
    {
        new ArchiveRestrictionInfo()
        {
            Name = "selectionId",
            Operator = "=",
            Values = new [] { selectionForFind.SelectionId.ToString() }
        }
    },
    new[] { searchEntity },
    0,
    int.MaxValue);

foreach (var listItem in results)
{
    string column1 = listItem.ColumnData[columns[0]].DisplayValue;
    string column2 = listItem.ColumnData[columns[1]].DisplayValue;
    Console.WriteLine($"{column1} {column2}");
}

Summary

This article has demonstrated how to search SuperOffice using the same routines used by SuperOffice Find. This way guarantees your applications receive the same results observed both in Selections and using the Find dialog.

© SuperOffice. All rights reserved.
SuperOffice |  Community |  Release Notes |  Privacy |  Site feedback |  Search Docs |  About Docs |  Contribute |  Back to top