Jump to: navigation, search

Scout/Tutorial/Lookup Calls


Scout
Wiki Home
Website
DownloadGit
Community
ForumsBlogTwitter
Bugzilla
Bugzilla


Scout
Wiki Home
Website
DownloadGit
Community
ForumsBlogTwitter
Bugzilla
Bugzilla


Local Lookup Calls

The usage of a Local Lookup Calls makes especially sense when a Code Type doesn't meet the requirements 100%, but some slight changes would make it match perfectly. In this case we can wrap a Local Lookup Call around the Code Type to remove or add values from or to the list without changing the Code Type's data.

Create a Local Lookup Call

So let's extend the CompanyRatingCodeType. After we've done that we'll assign the newly created Local Lookup Row to the CompanyRatingField on the CompanyForm.

Go to the Scout Explorer and open: client > Local Lookup Call, right-click and choose new Local Lookup Call…

Create a new Local Lookup Call according to the picture beyond.

Scout local lookupcall new.jpg


Local Lookup Calls have a function called execCreateLookupRows, which returns an ArrayList of LookUp Rows. All we have to do is filling this List with the required values.

So open the ExtendedCompanyRatingLookupCall and adjust it according to this code example:

protected List<LookupRow> execCreateLookupRows() throws ProcessingException {
    ArrayList<LookupRow> rows = new ArrayList<LookupRow>();
 
    // load the CompanyRatingCodeType from client cache
    ICodeType companyRating = CODES.getCodeType(CompanyRatingCodeType.class);
 
    // create new Lookup Row out of CompanyRatingCodeType's Codes
    ICode aCode = companyRating.getCode(CompanyRatingCodeType.ACode.ID);
    rows.add(new LookupRow(aCode.getId(), aCode.getText() + " Rating"));
 
    ICode bCode = companyRating.getCode(CompanyRatingCodeType.BCode.ID);
    rows.add(new LookupRow(bCode.getId(), bCode.getText() + " Rating"));
 
    ICode cCode = companyRating.getCode(CompanyRatingCodeType.CCode.ID);
    rows.add(new LookupRow(cCode.getId(), cCode.getText() + " Rating"));
 
    // create a new Lookup Row manually
    rows.add(new LookupRow(20100L, "not known"));
 
    return rows;
}

Adjust the CompanyRatingField on PersonForm

In a next step we assign the ExtendedCompanyRatingLookupService to the CompanyRatingField on the CompanyForm. Go to: client > Forms > CompanyForm > MainBox > CompanyRatingField, double-click and edit the properties according to the picture:

Scout local lookupcall ajust company rating field.jpg


This is all we have to do. The CompanyProcessService is still working and there's no need to change it. Let's start the application and test it:

Scout company rating field.jpg

Lookup Calls

Lookup Calls need services, which call the database to gather the required information. They are intelligent and powerful since they allow SQL queries. Nevertheless, always bear in mind that a database call costs a lot. Whenever possible try to use Local Lookup Calls or Code Types.

A Lookup query consists of three parts:

  • key: when the key (e.g. company_nr) is know
  • text: when the user types into the smart field
  • all: when the smart field is opened and scrolled through
This is what a query looks like:
SELECT KEY, DISPLAY_TEXT FROM TABLE
WHERE 1=1
<key> AND KEY = :key </key>
<text> AND UPPER(DISPLAY_TEXT) LIKE UPPER(:text || '%') </text>
<all></all>

No more than two columns must be given back. The first column is referenced as key (e.g. company_nr) and the second column is referenced as text to be displayed (e.g. BSI Business Systems Integration AG).

Create a Lookup Call

So let's implement our first lookup call:

Go to shared > Lookup Call and right-click, choose New Lookup Call… and fill the form with the information provided by the picture.

Scout lookup call new1.jpg

Press next to have a look at the additional classes and the configurations, which will be generated during the creation of a new Lookup Call.

Scout lookup call new2.jpg

Idea.png
Client and Server Communication
Hint: client and server have no direct links to each other. Every client call is bridged by tools stored in shared, which delegate the call to the server and deliver the results to the client. Whenever we want data from the server, we ask the corresponding interface for action.


The CompanyLookupCall class contains the method getConfiguredService, which returns the Interface ICompanyLookupService. Both, the class and the interface are located in the shared folder.

protected Class<? extends ILookupService> getConfiguredService() {
    return ICompanyLookupService.class;
}

The real implementation is situated in the CompanyLookupService in the server folder. So provide full functionality, we have to extend this service. Expand the tree like: server > Lookup Services and double-click the CompanyLookupService.

Adjust the method getConfiguredSqlSelect according to following example:

public String getConfiguredSqlSelect() {
    return "" +
        "SELECT COMPANY_NR, NAME FROM COMPANY " +
        "WHERE 1=1 " +
        "<key> AND COMPANY_NR = :key </key> " +
        "<text> AND UPPER(NAME) LIKE UPPER(:text || '%') </text> " +
        "<all></all>";
}

By now the Lookup Service is already completed and would work if used.

Add a SmartField to PersonForm

Let's go to the next step: we'll add a Smart Field to the PersonForm, with which we can choose and change the company.

Expand the PersonForm (client > Forms > PersonForm > MainBox ), right-click and choose New Form Field…

Pick Smart Field from the list, press Next and enter the information according to the picture below.

Scout company smartfield.jpg


There is no need to define a Code Type, just leave this field empty. After the CompanyField's creation, open it in the Properties Editor and set the Lookup Call property to CompanyLookupCall.

Scout company smartfield assign lc.jpg


As there is a new field on PersonForm, we shouldn't forget to update the Form Data. Right-click on PersonForm, select Update Form Data.

The Lookup Service and the Company Smart Field will already work, but the changes won't be wrote back to the database as the implementation in PersonProcessService is missing. Never the less, let's start the application in order to test the new functionality in the PersonForm.

Scout company smartfield preview.jpg


Before we adjust the PersonProcessService, we have to remove the variable CompanyNr from the PersonForm. This information will be stored from now on in the newly created Company Smart Field. Unfortunately, this means to refactor multiple parts of the PersonForm class.

Open client > Forms > PersonForm > Variables, right-click on CompanyNr choose Delete CompanyNr (Long)…

Don't forget to update the Form Data.

Scout delete company nr.jpg

Adjust the PersonProcessService

After the deletion of companyNr the compiler can't process the PersonTablePage anymore, because this class calls the member setCompanyNr on the PersonForm.

Open client > All pages > PersonTablePage, navigate to the NewPersonMenu's execAction method and change it according to the example:

protected void execAction() throws ProcessingException {
        PersonForm form = new PersonForm();
        form.getCompanyField().setValue(getCompanyNr());
        form.startNew();
        form.waitFor();
 
        if (form.isFormStored()) {
          reloadPage();
        }
}

Now everything's prepared to extend the PersonProcessService. Open server > Process Service > PersonProcessService.

Whenever we referenced to the company_nr, we used the SQL variable :companyNr throughout the three functions create, load and store. As we have deleted the companyNr variable, we should reference to the new Company Smart Field. So we have to replace all :companyNr's occurrences with :company (have a look at your PersonFormData to make sure that it has the same naming).

The functions should look like:

public PersonFormData create(PersonFormData formData) throws ProcessingException {
    if (!ACCESS.check(new CreatePersonPermission())) {
      throw new VetoException(Texts.get("AuthorizationFailed"));
    }
    SQL.selectInto("" +
        " SELECT MAX(PERSON_NR) + 1 " +
        " FROM PERSON " +
        " INTO :personNr ", formData);
 
    SQL.insert("" +
        " INSERT INTO PERSON (PERSON_NR, FIRST_NAME, LAST_NAME, PHONE, USERNAME, COMPANY_NR)" +
        " VALUES (:personNr, :firstName, :lastName, :phone, :username, :company) ", formData);
 
    return formData;
  }
 
  public PersonFormData load(PersonFormData formData) throws ProcessingException {
    if (!ACCESS.check(new ReadPersonPermission())) {
      throw new VetoException(Texts.get("AuthorizationFailed"));
    }
 
    SQL.selectInto("" +
        " SELECT FIRST_NAME, LAST_NAME, PHONE, USERNAME, COMPANY_NR " +
        " FROM PERSON " +
        " WHERE PERSON_NR = :personNr " +
        " INTO :firstName, :lastName, :phone, :username, :company ", formData);
    return formData;
  }
 
  public PersonFormData store(PersonFormData formData) throws ProcessingException {
    if (!ACCESS.check(new UpdatePersonPermission())) {
      throw new VetoException(Texts.get("AuthorizationFailed"));
    }
    SQL.update("" +
        " UPDATE PERSON SET" +
        " FIRST_NAME = :firstName, " +
        " LAST_NAME = :lastName, " +
        " PHONE = :phone, " +
        " USERNAME = :username, " +
        " COMPANY_NR = :company " +
        " WHERE PERSON_NR = :personNr ", formData);
    return formData;
  }

With this functionality it's possible to move a person between companies and to create a person from the company independent PersonTablePage, located in the StandardOutline as root element.