Mashup for LPA – Pending Work Units

Last week all employees at Lawson Product Development had a new kind of event called 20four. Its goal is to inspire and drive innovation. What we did? We were allowed to spend 24 hours doing whatever we wanted to do. No limitations – at all.

After 24 hours had passed we had 4 minutes to present what we did and then we voted for the best project. In this blog I’ll present the winning project, a LPA Mashup that displays pending work, created by Conny E. Special thanks to Conny for sharing his Mashup.

It is perhaps not innovative but it solves a business scenario and apperently this information was not easily accessable in Landmark, and that is what Mashups are for, bringing data together from different screens, programs and data sources.

Part of the User Experience team did a REST service that gets employee information from LDAP. Using our own internal service (with access to a photo database) the Mashup looks like this:

It is also possible to get employee information from Landmark and in that case the Mashup will look like this.

The Mashup uses Data Service controls to get Landmark data and events to hook it all together.

Here is the Mashup using Landmark to ge employee information.

<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:ui="clr-namespace:Mango.UI.Controls;assembly=Mango.UI" xmlns:mashup="clr-namespace:Mango.UI.Services.Mashup;assembly=Mango.UI">
  <Grid.ColumnDefinitions>
    <ColumnDefinition Width="Auto" />
    <ColumnDefinition Width="1*" />
  </Grid.ColumnDefinitions>
  <Grid.RowDefinitions>
    <RowDefinition Height="1*" />
    <RowDefinition Height="1*" />
    <RowDefinition Height="Auto" />
  </Grid.RowDefinitions>
<!-- This DataListPanel fetches all pending work units -->
  <mashup:DataListPanel Name="PendingWorkUnits" Margin="8" Grid.Row="0" Grid.Column="0" Grid.RowSpan="2">
    <mashup:DataListPanel.Events>
      <mashup:Events>
        <mashup:Event TargetName="PendingWorkUnits" SourceEventName="Startup" TargetEventName="List" />
      </mashup:Events>
    </mashup:DataListPanel.Events>
    <mashup:DataListPanel.DataService>
      <mashup:DataService Type="LANDMARK">
        <mashup:DataService.Operations>
          <mashup:DataOperation Name="List">
            <mashup:DataParameter Key="Landmark.DataArea" Value="lpa_m3" />
            <mashup:DataParameter Key="Landmark.BusinessClass" Value="PfiWorkunit" />
            <mashup:DataParameter Key="Landmark.OutputFields" Value="PfiWorkunit,WorkTitle,FlowDefinition,ElapsedTimeComponentsText" />
            <mashup:DataParameter Key="Landmark.FilterFields" Value="" />
            <mashup:DataParameter Key="Landmark.MaxReturnedRecords" Value="300" />
            <mashup:DataParameter Key="Landmark.ListName" Value="ActionPendingWorkunits" />
          </mashup:DataOperation>
        </mashup:DataService.Operations>
      </mashup:DataService>
    </mashup:DataListPanel.DataService>
    <ListView ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
      <ListView.View>
        <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
          <GridView.Columns>
            <GridViewColumn Header="Id" DisplayMemberBinding="{Binding [PfiWorkunit]}" />
            <GridViewColumn Header="Title" DisplayMemberBinding="{Binding [WorkTitle]}" />
            <GridViewColumn Header="Process Flow" DisplayMemberBinding="{Binding [FlowDefinition]}" />
            <GridViewColumn Header="Elapsed Time" DisplayMemberBinding="{Binding [ElapsedTimeComponentsText]}" />
          </GridView.Columns>
        </GridView>
      </ListView.View>
    </ListView>

  </mashup:DataListPanel>
    <!-- This DataListPanel fetches the names of all users and roles that has been assigned to the User Action node
    Next step would be to expand Groups to see which users that exists in the group
    The name components (below) will not work for groups -->
    <mashup:DataListPanel Name="QueueTask" Margin="8" Grid.Row="0" Grid.Column="1">
    <mashup:DataListPanel.Events>
      <mashup:Events>
        <mashup:Event SourceName="PendingWorkUnits" SourceEventName="CurrentItemChanged" TargetEventName="List">
          <mashup:Parameter SourceKey="PfiWorkunit" TargetKey="PfiWorkunit" />
        </mashup:Event>
      </mashup:Events>
    </mashup:DataListPanel.Events>
    <mashup:DataListPanel.DataService>
      <mashup:DataService Type="LANDMARK">
        <mashup:DataService.Operations>
          <mashup:DataOperation Name="List">
            <mashup:DataParameter Key="Landmark.DataArea" Value="lpa_m3" />
            <mashup:DataParameter Key="Landmark.BusinessClass" Value="PfiQueueTask" />
            <mashup:DataParameter Key="Landmark.OutputFields" Value="PfiWorkunit,PfiTask.TaskName,PfiActivity" />
            <mashup:DataParameter Key="Landmark.FilterFields" Value="PfiWorkunit" />
            <mashup:DataParameter Key="Landmark.MaxReturnedRecords" Value="200" />
            <mashup:DataParameter Key="Landmark.ListName" Value="QueueTaskList" />
          </mashup:DataOperation>
        </mashup:DataService.Operations>
      </mashup:DataService>
    </mashup:DataListPanel.DataService>
    <ListView ItemsSource="{Binding Items}" Style="{DynamicResource styleListView}" ItemContainerStyle="{DynamicResource styleListViewItem}">
      <ListView.View>
        <GridView ColumnHeaderContainerStyle="{DynamicResource styleGridViewColumnHeader}">
          <GridView.Columns>
            <GridViewColumn Header="Id" DisplayMemberBinding="{Binding [PfiWorkunit]}" />
            <GridViewColumn Header="Flow Activity Nr" DisplayMemberBinding="{Binding [PfiActivity]}" />
            <GridViewColumn Header="Role/User" DisplayMemberBinding="{Binding [PfiTask.TaskName]}" />
          </GridView.Columns>
        </GridView>
      </ListView.View>
    </ListView>
  </mashup:DataListPanel>

  <GroupBox Header="Who should do What?" Grid.Row="1" Grid.Column="1" Margin="8">
    <StackPanel Orientation="Vertical">

      <!-- This DataDetailPanel fetches the name for the user action node that the process flow have reached from Landmark-->
      <mashup:DataDetailPanel Name="UserActionDetail" Margin="8">
        <mashup:DataDetailPanel.Events>
          <mashup:Events>
            <mashup:Event SourceName="QueueTask" SourceEventName="CurrentItemChanged" TargetEventName="Get">
              <mashup:Parameter SourceKey="PfiWorkunit" TargetKey="PfiWorkunit" />
              <mashup:Parameter SourceKey="PfiActivity" TargetKey="PfiActivity" />
            </mashup:Event>
          </mashup:Events>
        </mashup:DataDetailPanel.Events>
        <mashup:DataDetailPanel.DataService>
          <mashup:DataService Type="LANDMARK">
            <mashup:DataService.Operations>
              <mashup:DataOperation Name="Get">
                <mashup:DataParameter Key="Landmark.DataArea" Value="lpa_m3" />
                <mashup:DataParameter Key="Landmark.BusinessClass" Value="PfiActivity" />
                <mashup:DataParameter Key="Landmark.FilterFields" Value="PfiWorkunit,PfiActivity" />
                <mashup:DataParameter Key="Landmark.ListName" Value="ActivityList" />
                <mashup:DataParameter Key="Landmark.OutputFields" Value="PfiActivity,ActivityName,PfiWorkunit" />
              </mashup:DataOperation>
            </mashup:DataService.Operations>
          </mashup:DataService>
        </mashup:DataDetailPanel.DataService>
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="8" />
            <ColumnDefinition Width="Auto" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
          <Label Content="Next Step:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
          <TextBlock Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="{Binding [ActivityName]}" Margin="0,0,0,0" />
        </Grid>
      </mashup:DataDetailPanel>

      <!-- This DataDetailPanel fetches the name for an Actor from Landmark and could be used if you don't have another REST service-->
      <mashup:DataDetailPanel Name="LMRKUser" Margin="8">
        <mashup:DataDetailPanel.Events>
          <mashup:Events>
            <mashup:Event SourceName="QueueTask" SourceEventName="CurrentItemChanged" TargetEventName="Get">
              <mashup:Parameter SourceKey="PfiTask.TaskName" TargetKey="Actor" />
            </mashup:Event>
          </mashup:Events>
        </mashup:DataDetailPanel.Events>
        <mashup:DataDetailPanel.DataService>
          <mashup:DataService Type="LANDMARK">
            <mashup:DataService.Operations>
              <mashup:DataOperation Name="Get">
                <mashup:DataParameter Key="Landmark.DataArea" Value="lpa_m3" />
                <mashup:DataParameter Key="Landmark.BusinessClass" Value="Actor" />
                <mashup:DataParameter Key="Landmark.OutputFields" Value="Actor,PersonName.GivenName,PersonName.FamilyName" />
                <mashup:DataParameter Key="Landmark.FilterFields" Value="Actor" />
                <mashup:DataParameter Key="Landmark.MaxReturnedRecords" Value="200" />
              </mashup:DataOperation>
            </mashup:DataService.Operations>
          </mashup:DataService>
        </mashup:DataDetailPanel.DataService>
        <Grid>
          <Grid.ColumnDefinitions>
            <ColumnDefinition Width="Auto" />
            <ColumnDefinition Width="8" />
            <ColumnDefinition Width="Auto" />
          </Grid.ColumnDefinitions>
          <Grid.RowDefinitions>
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
            <RowDefinition Height="Auto" />
          </Grid.RowDefinitions>
          <Label Content="Actor:" Grid.Row="0" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
          <TextBlock Grid.Row="0" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="{Binding [Actor]}" Margin="0,0,0,0" />
          <Label Content="Given Name:" Grid.Row="1" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
          <TextBlock Grid.Row="1" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="{Binding [PersonName.GivenName]}" Margin="0,0,0,0" />
          <Label Content="Family Name:" Grid.Row="2" Grid.Column="0" HorizontalAlignment="Left" VerticalAlignment="Center" />
          <TextBlock Grid.Row="2" Grid.Column="2" HorizontalAlignment="Stretch" VerticalAlignment="Center" Text="{Binding [PersonName.FamilyName]}" Margin="0,0,0,0" />
        </Grid>
      </mashup:DataDetailPanel>

    </StackPanel>
  </GroupBox>
    <ui:StatusBar Name="StatusBar" Grid.Row="3" Grid.Column="0" Grid.ColumnSpan="2" />
</Grid>

There were a few projects involving Mashups and Smart Office. My vote for best project went to Thomas A in Denmark and his Lawson Smart Office Sudoku Widget.

First I was a bit skeptical about the event, “do what you feel like”, but it turned out to be a great event.

4 thoughts on “Mashup for LPA – Pending Work Units

  1. thibaudatwork

    Tjena Karin. My customer wants to see the Inbasket in a Mashup, and be able to take action (Approve/Reject) from it. When I run your Mashup sample above I get the error “Infor Smart Office ! Error. Service for type LANDMARK is not registered.” Is your example for S3 only or will it work for M3 as well? I have Smart Office 10.1.1.0.19 for M3 13.1, I see the TriggerPanel Control in Mashup Designer. Also, the PF group in the Profile Editor is enabled with seemingly correct values in the configuration. However, the Landmark group in the Profile Editor is not set and not enabled. Would that explain the problem, and how do I configure it? Thanks. /Thibaud

    Reply
    1. thibaudatwork

      Never-mind. It works. I copy/pasted the Port/Host/Protocol values from the PF group to the Landmark group, enabled Landmark configuration, saved the profile, logoff/logon, and now the Mashup correctly displays the Pending WorkUnits and details. The new question is: do you know how to take action (ex: Approve/Reject) from a WorkUnit? Thanks. /Thibaud

      Reply
      1. karinpb Post author

        Hi,
        I don’t know how to take action. They are dynamic so I would not expect them to be accessible from a Mashup in an easy way. I’ll only tested actions on the business objects.

      2. thibaudatwork

        To all, I got the following two answers:

        1) James J said we can use a Landmark transaction node for taking actions, for example: _dataArea=”” & _module=”pfi” & _objectName=”PfiWorkunit” & _actionName=”TakeAction” & _actionOperator=”NONE” & _actionType=”CreateUpdateDelete” & _pageSize=”30″ & PfiWorkunit=”Workunit number goes here (numbers only)” & Action=”Action goes here (this is case sensitive)” & Subject=”Subject goes here (optional)” & Message=”Message goes here (optional)”.

        2) And Alfred C said there is a new IPA servlet released this year that can be used to take an action, for example: /bpm/inbox/dispatch? dataArea=lmtest&workunit=28&actId=2&task=Approver&reason=MyReason&message=MyMessage&action=yes

        /Thibaud

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s