Lawson Reporting

Lawson Reporting - Automation Tips and Tricks

Using Perl to Access the Lawson DME in LSF9 Environment

I wrote a previous article about using perl to query the Lawson DME for 8.0.3 environment.  We just got the LSF9 environment (not apps), and to my surprise, the authentication is different between the two.

The authentication for Lawson DME in 8.0.3 environment uses http basic authentication.

The authentication for LSF9 environment uses Lawson's own server side authentication.

Obviously this means that the method of accessing the DME from perl needs to change.  The perl code design has to change from using built in LWP credentials method of navigating through HTTP basic auth to simulating a login on the Lawson login page, capturing the cookie, and bringing it along with to make the request to the DME.

Here is the new code.  The function takes 3 arguments, a URL, userame, and password.  We only have a secure https address to access our DME, so that is why the Crypt::SSLeay library is needed.

 

###############
# gets the raw Lawson DME response from the server from a https secure site
# arguments:
#   URL - full URL, is designed to use https URLs
#   Username - Lawson portal username
#   Password - Lawson portal password
###############
sub getLawsonDMEResponse($$$) {
  use LWP::UserAgent;
  use Crypt::SSLeay;
  use HTML::Form;
  my $url = shift;
  my $username = shift;
  my $password = shift;

  my $ua = LWP::UserAgent->new;
  $ua->cookie_jar( {} ); # cookies needed for login authentication
  my $response = $ua->get($url);
  
  if($response->is_success) {
    # parse loginForm form and enter the values for the _ssoUser and _ssoPass field names
    my @forms = HTML::Form->parse($response);
    $forms[0]->value("_ssoUser",$username);
    $forms[0]->value("_ssoPass",$password);
    my $loginButton = $forms[0]->find_input("_ssoLogin");
    $loginButton->disabled(0);
    my $response2 = $ua->request($forms[0]->click("_ssoLogin"));
  
    if($response2->is_success) {
      # its OK, response 2 never succeeds, oh well, all we want is a cookie
      # it will fail with a 302 moved
    }
    else {
      # go ahead and call the URL we want
      my $response3 = $ua->get($url);
      if($response3->is_success) {
        return $response3->content;
      }
      else {
        print "URL request failed for url:$url\n";
      }
    }
  }
  else {
    die "Problems getting through login screen\n";
  }
}

Using Lawson Office Addins Index Range as a Wildcard

One my biggest frustrations with using Lawson Office Addins Query Wizard is that the Index Key sets are hard to use.  I could never use them until I figured out that you have to define every index in order.  You can't skip one or else it won't work.  But there are large performance gains that can be found by using indexes that can make your Lawson Reporting more efficient.

Here is an example situation:

I want to look for employees in a specific department.  Process level doesn't matter.

From the EMPLOYEE table, I see EMPSET2 is:

COMPANY
PROCESS-LEVEL
DEPARTMENT
EMPLOYEE

I can't just do this:

COMPANY                    1
PROCESS-LEVEL     
DEPARTMENT             1001
EMPLOYEE

It doesn't work at all.  I get some stuff back, but it definitely doesn't match my query.

So you might be saying, why not just put a wildcard in there for PROCESS-LEVEL.  However, there really isn't a wildcard character.

One thing I do know is that ranges work.  And really, the function of a wildcard is really just an infinitely big range.  So let's run with that.  Why don't we just pick a sufficiently large range for one of the inner indices.

Let's use the same example:
I want to pull all employees in our HR company that are in any process level, but a specific department.

From the EMPLOYEE table, I see EMPSET2 is:

COMPANY
PROCESS-LEVEL
DEPARTMENT
EMPLOYEE

We learned that we need a wildcard for PROCESS-LEVEL, but a specific value for DEPARTMENT.

Well, to do a range in the Query Wizard, you use the little arrow thing with a dash and a greater than sign, like this:

->

So if I know that all my PROCESS-LEVELs are between 00 and 99, I can just set up the indices like this:

COMPANY                      1
PROCESS-LEVEL        00->99
DEPARTMENT               1001
EMPLOYEE

The 00->99 effectively acts as a wildcard, because you know with your system, that there won't be any higher or lower.  I think you can see how to apply this to pretty much any situation.

If the field is a character field, it gets a little trickier, but you can figure it out.  Its hard to figure out what the values of characters are.  It actually depends on the database behind the scenes.  However, a little testing can get you there.

Usually, numbers are a lower value than alpha characters.  And sometimes, special characters like _, or even *, or just a blank space, have certain values.  See an example of an ASCII table.  But, this ASCII table doesn't represent the specific ASCII table of values that you particular database is using.  I actually had a ticket with Lawson on this issue that opened my eyes up to this.

So anyways, sorry to be rambling on.  But if you had an alpha field that you wanted to emulate a wildcard using a range, you could do this:

000000->ZZZZZZ

And date fields can be done using a similar philosophy, but you have to use a different format for the year, yyyymmdd.  You can pick a magic date like 1/1/1970 to 1/1/2020 and do something like this.

19700101->20200101

So really, now that we know how to use indices better, Lawson Reporting using the Micorosft Office Addins is just a little easier.

Lawson Reporting using DME from perl

I have done a lot of reporting in Lawson using the Addins Query Wizard, but because I always have the need to make Lawson Reporting faster and automated, the Query Wizard shows its weaknesses.  You simply can't automate Lawson Reporting through the Addins.  But one thing that is a feature of the Addins that opens up a lot of Lawson automated reporting solutions is that you can get the URL that is generated by the Addins to use from any method that can access a web site.  I will show you how to automate Lawson Reporting using DME from perl.

Sometimes, Lawson reporting calls for more powerful measures than excel can handle through the Office Add-ins, and well, I know that a scripting language like perl is more than capable through my years of prior experience doing data analysis.  Sometimes, 65536 data records is a limitation of Excel that eliminates it as a solution option when trying to solve a Lawson reporting problem.  Bring on perl!

So my goal was to figure out how to use perl to query Lawson data through the DME that is the same method used by the Office Addins.  All the Office Add-ins really do is generate a web URL that passes arguments to the Lawson Reporting DME interface. This is important in our environment where our Lawson system is hosted, so we don't have the database connections or server-side programming that in-house Lawson setups would have.  So this means that I need to use HTTP access from perl to navigate through the HTTP basic authentication to query using the DME.  This is the only option that we have that would use Lawson security, as our ODBC connection is an all-access connection. Any Lawson Reporting solution should obey security access rules if you ever plan to distribute it.

So let me show you how to use perl to whip the Lawson data into shape.

Step 1)

Find a DME query.  Easy.  Just use the Lawson Office Add-ins to develop the query, run the query once, click on the little magnifying glass at the top of the Office Add-ins tool to get the full DME call.  Done!

Step 2)

Very simple perl code.  For this example, pulling Company, Employee, first and last name from the EMPLOYEE table in our PROD environment via the DME query.

#!/usr/bin/perl
use strict;
use LWP::UserAgent;

Next goes your DME query that you pulled from the Office add-ins.

# copy and paste the URL directly from the Office Add-ins Query Wizard
# IMPORTANT: if your server has a port, you NEED to add it in, otherwise the auth won't work
my $simpleURL = "http://my.lawson.server.com:30077/cgi-lawson/dme.exe?PROD=PROD&
  FILE=EMPLOYEE&INDEX=EMPSET1&KEY=1&
  FIELD=COMPANY;EMPLOYEE;FIRST%2DNAME;LAST%2DNAME&MAX=600&
  OUT=CSV&DELIM=%09&NOHEADER=TRUE";

Next, initialize the perl LWP::UserAgent module to do the HTTP request.  If you don't know your authentication realm, copy and paste the DME query into a blank web browser window, hit enter, and see what the prompt says.  Or just run this script, and an error will pop up that shows you, more details on that down below.

my $ua = LWP::UserAgent->new;
# set the basic HTTP auth credentials
# arguments are server:port, authentication realm, username => password
$ua->credentials('my.lawson.server.com:30077','Lawson Restricted Access','username'=>'password');
my $response = $ua->get($simpleURL);

Now we will verify the response, and print out an error that will contain the reason for failure.

 

if($response->is_success) {
  print $response->content;
}
else {
  # this will print out any errors
  # IMPORTANT: This also will tell you what your auth realm is if you don't know it
  die "Error: ", $response->header('WWW-Authenticate') ||
  'Error accessing', "\n", $response->status_line, "\n at $url\n Aborting";
}

Here is the full code listing for you copy and pasters.

#!/usr/bin/perl
use strict;
use LWP::UserAgent;

# copy and paste the URL directly from the Office Add-ins Query Wizard
# IMPORTANT: if your server has a port, you NEED to add it in, otherwise the auth won't work
my $simpleURL = "http://my.lawson.server.com:30077/cgi-lawson/dme.exe?PROD=PROD&
  FILE=EMPLOYEE&INDEX=EMPSET1&KEY=1&
  FIELD=COMPANY;EMPLOYEE;FIRST%2DNAME;LAST%2DNAME&MAX=600&
  OUT=CSV&DELIM=%09&NOHEADER=TRUE";

my $ua = LWP::UserAgent->new;
# set the basic HTTP auth credentials
# arguments are server:port, authentication realm, username => password
$ua->credentials('my.lawson.server.com:30077','Lawson Restricted Access','username'=>'password');
my $response = $ua->get($simpleURL);

if($response->is_success) {
  print $response->content;
}
else {
  # this will print out any errors
  # IMPORTANT: This also will tell you what your auth realm is if you don't know it
  die "Error: ", $response->header('WWW-Authenticate') ||
    'Error accessing', "\n", $response->status_line, "\n at $url\n Aborting";
}

Syndicate content