Forums >> Programming >> Proof of Concept (POC) >>
Creating Mobile Applications using RPG, the IBM i, and Canvas



Posted:
bvstone

Creating Mobile Applications using RPG, the IBM i, and Canvas

 
Creating Mobile Applications using RPG, the IBM i, and Canvas

The subject of creating applications for mobile devices comes up quite often.  There are normally many solutions provided, some theoretical, others proven with actual use.  So I thought I would share my experience with creating mobile applications on the IBM i.

In working with a customer we needed a way to dispatch technicians to locations to perform installations, fixes or even training.  Paper tickets were being used before.  These tickets were used to log the time spent, any materials used, as well as obtain a signature from the customer to show the work that was done.

We needed a way to make this work on mobile digital devices such as iPhones, iPads, Android devices and Blackberries.

My first thought was create a web application.  Since they can be cross platform that would solve that issue.  Then we ran into an issue where during the work, not only did we need to capture signatures, but also be able to take pictures of things we could attach to the work ticket.  That made it more complicated than a web application could handle.  Yes, it's possible, but is it worth the fight?

Then I started looking into "apps that create apps".  One was from a company named Canvas (www.gocanvas.com).  After 15 minutes of playing with it, I knew I was onto something good.

What you can do with Canvas is create apps for your company.  You get a WYSIWYG interface to build the forms used by the apps and control the flow of the app.  In this case we needed one that would work as a dispatch for technicians.  Each technician installs the Canvas app and creates an account at Canvas.  Then, when we want to alert a specific technician of work to do, we use a Web Service (or RESTful) request to send information about the job to the technician (or technicians).

In the following posts I will describe the steps used.  More will be added to this as time goes on, but hopefully it will provide enough information to help you with your project.



Posted:
bvstone

Creating the App using Canvas

 
Creating the App using Canvas

When you first log on to your Canvas account, you are given a few templates to work with.  Because our form was quite simple, we chose to start from scratch.

Selecting the MyApps link will list any apps you have created and that are provided by default.  You have the option to edit apps, or create a new one.

You'll notice in the app list there is a version associated with each one.  This idea of versioning is quite useful in case you mess up during an edit and need to revert to an older version.

When we enter the editor we are given a WYSIWYG interface that allows you to create "screens", add items to each screen, as well as work with the flow of each app (ie, which order the screens will appear).

Each item on each screen can be text, numeric, date, or even calculated.  Each field can also be set to a default value in the app itself as well as have it's value set when you initiate the creation of an app to be sent to a user.  

In this example we will send a dispatch to a technician.  The dispatch will include the address of the customer and also allow them to use their mobile device's GPS system to get them there.  Obviously the address will be different for each dispatch and that value can be set when the dispatch is created, which we will see more of later.

As you can see, the tools provided by Canvas make things very easy to create and update. 


Last edited 10/02/2014 at 13:11:05


Posted:
bvstone

Initiating an Event

 
Initiating an Event

In our example we are working with a dispatch system to send technicians to locations to perform specific tasks.  

Our online system already allowed the creation of work tickets and allowed us to assign technicians to that specific ticket.  

To incorporate the use of Canvas and the apps, we simply added an option to our work ticket screen to create a dispatch and alert the technician of a job that was ready for them.

In the screen capture above we see that we have a work ticket.  To the left are employees that are assigned to the ticket.  To the right are employees that are available to be assigned to the ticked.

In the list of assigned employees we have a Canvas logo that when clicked, will initiate the creation of a dispatch for that specific employee.

In this next screen shot we see the results after clicking the Canvas logo next to the user of "Brad Stone".  This screen alerts us that in the background there is a process of creating and sending the dispatch to the user.  This is done, in this case, using the GETURI application to make a POST to the Canvas servers.

The POST consists of XML that not only defines which app we want to send (in this case, a Dispatch), but it also defines the values for any data that we want to prefill in the app when the user opens it.  An example of the POST and XML created (using the eRPG SDK, which could also be done with CGIDEV2 or other tools) is as follows:

POST /apiv2/dispatch_items?username=xxxxxxxx&password=xxxxxxxx HTTP/1.0
Accept: text/html
Host: www.gocanvas.com
Content-type: application/x-www-form-urlencoded
Content-length: 907

<?xml version="1.0" encoding="utf-8"?> 
<List> 
	<DI FormName="Dispatch" Description="this is a work ticket (41)" User="bvstone@bvstools.com"> 
		<DIEntry Label="ticket_id" Value="41"/> 
		<DIEntry Label="order_date" Value="04/17/2014"/> 
		<DIEntry Label="customer_email" Value="cindysmith@cindy.com"/> 
		<DIEntry Label="customer_business" Value=""/> 
		<DIEntry Label="customer_contact" Value="Cindy Smith"/> 
		<DIEntry Label="customer_add1" Value="111 Main Street"/> 
		<DIEntry Label="customer_add2" Value=""/> 
		<DIEntry Label="customer_city" Value="Fairhope"/> 
		<DIEntry Label="customer_state" Value="AL"/> 
		<DIEntry Label="customer_zip" Value="60004"/> 
		<DIEntry Label="customer_phone" Value="18478705236"/> 
		<DIEntry Label="default_labor_rate" Value="99.99"/> 
		<DIEntry Label="has_parts" Value="true"/> 
		<DIEntry Label="has_labor" Value="true"/> 
	</DI> 
</List>

The POST is made to a specific URL and also sends the user id and password of an account holder in Canvas. 

The XML contains information such as the name of the form to send (in this case, our Dispatch form), which user to send it to, and any default values.

Once the POST is complete the Canvas application returns XML with any errors, messages, or information.


Last edited 10/02/2014 at 13:23:42


Posted:
bvstone

Receiving the Dispatch on the Mobile Device

 
Receiving the Dispatch on the Mobile Device

Once the dispatch is sent to a user they will receive a notification on their device that a new item is available.

Then can click on the notification or the Canvas app itself to see the new dispatches that are ready for them to act on.

We see here by the icon next to the work ticket that this one is new and needs to be completed.

When the user clicks on the ticket, it is opened with the default values that were sent in the XML POST in the previous step.

The user will then go through each screen and fill out the information.  This particular design allows them to enter multiple details lines for parts used as well as time spent on each job.

Finally, when they are done they present the device to the end customer to get a signature saying that the work has been completed.

The customers signature is then captured.

When everything is done, the information is submitted back to Canvas and made available for our application to retrieve any data, including images and signatures.

As of this writing there really isn't a way to trigger our server to tell us that a dispatch has been completed, but according the support at Canvas it is something they are looking into.

 


Last edited 10/02/2014 at 14:27:52


Posted:
bvstone

Retrieving the App Data back to your IBM i

 
Retrieving the App Data back to your IBM i

Once a dispatch is done, we need some way to retrieve the information that was stored in the app for the specific dispatch.

The information is available for download manually from the Canvas page under the "Submissions" menu as shown here:

As stated, at this time there really is no way to trigger the download of the data when the dispatch is submitted from the mobil device, so instead we have a manual refresh process we use.  

The manual submission triggers another POST using GETURI to the Canvas site to find any new submissions that are made.  

A sample of the code used is as follows:

     H DFTACTGRP(*NO) BNDDIR('ERPGSDK')
      ****************************************************************
      * Prototypes                                                   *
      ****************************************************************
     D SUBMISSION      PR
     D                              128
     D                             1024
     D SUBMISSION      PI
     D   inKey                      128
     D   outErrorMsg               1024
      ****************************************************************
      /COPY GETURI/QCOPYSRC,GETURICOPY
      /COPY QCOPYSRC,P.APPSTAT
      /COPY qcopysrc,p.pdocxml
      /COPY qcopysrc,p.libl
      ****************************************************************
      * Work Variables
     D xmlFile         s            500a   varying
     D ignoreMe        s              1a
     D GetError        s               n
     D rc              S             10i 0
      ****************************************************************
      /free
       outErrorMsg = ' ';
       #appstat_setStatus(inKey:'Retrieving Submissions...');
       xmlFile = '/tmp/canvassubmissions.xml';
       #pushLib('GETURI');
       EXSR $LoadParms;
       EXSR $GETURI;
       #popLib('GETURI');

       if (not GetError);
         #appstat_setStatus(inKey:'Processing Submissions...');
         rc = #pdocxml_setKey(inKey);
         rc = #pdocxml_setID('submission');
         rc = #pdocxml_clearErrors();
         rc = #pdocxml_loadRefs();
         xml-sax %handler(#pdocxml_xmlHandler:ignoreMe)
              %XML(xmlFile: 'doc=file');
       else;
         outErrorMsg = GetUri_Msg;
       endif;

       *inlr = *on;

       //***************************************************************
       //* Load GETURI Parameters
       //***************************************************************
       BegSr $LoadParms;

         CLEAR GetUri_In;
         GI_URI = 'https://www.gocanvas.com/apiv2/submissions.xml?' +
                  'username=xxxxxxxx&password=xxxxxxxxx&' +
                  'form_name=Dispatch';
         GI_ReqMeth = 'POST';
         GI_SSL   = '*YES';
         GI_Port   = 443;
         GI_CCSID  = 1208;
         GI_CodPag  = 1208;
         GI_OutType   = '*STMF';
         GI_Stmf = xmlFile;
         GI_SprHead = '*YES';
         GI_Debug = '*YES';

       EndSr;
       //***************************************************************
       //* Call GETURI
       //***************************************************************
       BegSr $GETURI;

      /end-free
     C                   CALL      'GETURIRG'                           99
     C                   PARM                    GetUri_In
     C                   PARM                    GetUri_Out
     C                   PARM                    GetUri_Head
     C                   PARM                    GetUri_Data
     C                   PARM                    GetUri_MsgCd
     C                   PARM                    GetUri_Msg
      /free

         GetError = (%scan('200 OK':GetUri_Head) <= 0) or (*IN99);

       EndSr;

      /end-free

The POST looks like the following:

POST /apiv2/submissions.xml?username=xxxxxx&password=xxxxxxx&form_name=Dispatch HTTP/1.0
Accept: text/html
Host: www.gocanvas.com
Content-type: application/x-www-form-urlencoded
Content-length: 0

What this request is doing is saying "retrieve all the data for any submissions with the form name of Dispatch.

The data returned is as follows:

<?xml version="1.0" encoding="UTF-8"?>
<CanvasResult>
 <TotalPages>1</TotalPages><CurrentPage>1</CurrentPage><Submissions><Submission Id="8092165">
  <Form Id="700427">
    <Name>Dispatch</Name>
    <Status>published</Status>
    <Version>14</Version>
  </Form>
  <Date>2014.10.02 18:33:50</Date>
  <DeviceDate>2014.10.02 18:31:12</DeviceDate>
  <UserName>bvstone@bvstools.com</UserName>
  <FirstName>Bradley</FirstName>
  <LastName>Stone</LastName>
  <ResponseID>63fff60953a2c4cf-1412269994795</ResponseID>
  <Sections>
    <Section>
    <Name>Customer Information</Name>
    <Screens>
      <Screen>
      <Name>Customer Information</Name>
            <Responses>
              <Response>
        <Label>ticket_id</Label>
        <Value>41</Value>
        <Type>Integer</Type>
        </Response>
        <Response>
        <Label>order_date</Label>
        <Value>04/17/2014</Value>
        <Type>Date</Type>
        </Response>
        <Response>
        <Label>customer_email</Label>
        <Value>cindysmith@cindy.com</Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_business</Label>
        <Value></Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_contact</Label>
        <Value>Cindy Smith</Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_add1</Label>
        <Value>111 Main Street</Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_add2</Label>
        <Value></Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_state</Label>
        <Value>AL</Value>
        <Type>Value List</Type>
        </Response>
        <Response>
        <Label>customer_city</Label>
        <Value>Fairhope</Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_zip</Label>
        <Value>60004</Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>customer_phone</Label>
        <Value>18478705236</Value>
        <Type>Text Box</Type>
        </Response>
            </Responses>
      </Screen>
    </Screens>
    </Section>
    <Section>
    <Name>Description of Work Performed</Name>
    <Screens>
      <Screen>
      <Name>Description of Work Performed</Name>
            <Responses>
              <Response>
        <Label>work_location</Label>
        <Value></Value>
        <Type>Text Box</Type>
        </Response>
        <Response>
        <Label>work_description</Label>
        <Value>install new VOIP phones</Value>
        <Type>Multi-Line Text</Type>
        </Response>
        <Response>
        <Label>work_gps</Label>
        <Value></Value>
        <Type>GPS</Type>
        </Response>
        <Response>
        <Label>default_labor_rate</Label>
        <Value>99.99</Value>
        <Type>Decimal</Type>
        </Response>
        <Response>
        <Label>has_parts</Label>
        <Value>True</Value>
        <Type>Checkbox</Type>
        </Response>
        <Response>
        <Label>has_labor</Label>
        <Value>True</Value>
        <Type>Checkbox</Type>
        </Response>
            </Responses>
      </Screen>
    </Screens>
    </Section>
    <Section>
    <Name>Parts List</Name>
    <Screens>
      <Screen>
      <Name>Parts List</Name>
        <ResponseGroups>
        <ResponseGroup>
          <Response>
          <Label>part_qty</Label>
          <Value>5</Value>
          <Type>Integer</Type>
          </Response>
          <Section>
          <Name>Parts List (Detail)</Name>
          <Screens>
            <Screen>
            <Name>Parts List</Name>
                  <Responses>
                    <Response>
              <Label>part_number</Label>
              <Value>phones</Value>
              <Type>Text Box</Type>
              </Response>
              <Response>
              <Label>part_desc</Label>
              <Value>voip phones</Value>
              <Type>Text Box</Type>
              </Response>
              <Response>
              <Label>part_each</Label>
              <Value></Value>
              <Type>Decimal</Type>
              </Response>
              <Response>
              <Label>part_total</Label>
              <Value>0.00</Value>
              <Type>Calculation</Type>
              </Response>
                  </Responses>
            </Screen>
          </Screens>
          </Section>
        </ResponseGroup>
        <ResponseGroup>
          <Response>
          <Label>part_qty</Label>
          <Value>20</Value>
          <Type>Integer</Type>
          </Response>
          <Section>
          <Name>Parts List (Detail)</Name>
          <Screens>
            <Screen>
            <Name>Parts List</Name>
                  <Responses>
                    <Response>
              <Label>part_number</Label>
              <Value>cable</Value>
              <Type>Text Box</Type>
              </Response>
              <Response>
              <Label>part_desc</Label>
              <Value></Value>
              <Type>Text Box</Type>
              </Response>
              <Response>
              <Label>part_each</Label>
              <Value></Value>
              <Type>Decimal</Type>
              </Response>
              <Response>
              <Label>part_total</Label>
              <Value>0.00</Value>
              <Type>Calculation</Type>
              </Response>
                  </Responses>
            </Screen>
          </Screens>
          </Section>
        </ResponseGroup>
        </ResponseGroups>
      </Screen>
    </Screens>
    </Section>
    <Section>
    <Name>Labor</Name>
    <Screens>
      <Screen>
      <Name>Labor</Name>
        <ResponseGroups>
        </ResponseGroups>
      </Screen>
    </Screens>
    </Section>
    <Section>
    <Name>Contract Totals</Name>
    <Screens>
      <Screen>
      <Name>Contract Totals</Name>
            <Responses>
              <Response>
        <Label>complete_date</Label>
        <Value>10/02/2014</Value>
        <Type>Date</Type>
        </Response>
        <Response>
        <Label>subtotal_parts</Label>
        <Value>0.00</Value>
        <Type>Summary</Type>
        </Response>
        <Response>
        <Label>subtotal_labor</Label>
        <Value>0.00</Value>
        <Type>Summary</Type>
        </Response>
        <Response>
        <Label>subtotal</Label>
        <Value>0.00</Value>
        <Type>Calculation</Type>
        </Response>
        <Response>
        <Label>tax_rate</Label>
        <Value>7</Value>
        <Type>Decimal</Type>
        </Response>
        <Response>
        <Label>total_tax</Label>
        <Value>0.00</Value>
        <Type>Calculation</Type>
        </Response>
        <Response>
        <Label>total_amount</Label>
        <Value>0.00</Value>
        <Type>Calculation</Type>
        </Response>
            </Responses>
      </Screen>
    </Screens>
    </Section>
    <Section>
    <Name>Signature</Name>
    <Screens>
      <Screen>
      <Name>Signature</Name>
            <Responses>
              <Response>
        <Label>Customer Signature</Label>
        <Value>502357631</Value>
        <Type>Signature</Type>
        </Response>
            </Responses>
      </Screen>
    </Screens>
    </Section>
  </Sections>
</Submission></Submissions> </CanvasResult>

As shown, the data returned will allow us to get the value of anything entered by the user's mobile device.  For any images (including signatures) a URL is provided to be able to either reference or download.

The data is retrieved as XML and parsed using the built in SAX parser.  Once compete, we see the new submission in the list and can view it's details (the last one in the list that is highlighted yellow).

 

 


Last edited 10/02/2014 at 14:11:49


Reply




Copyright 1983-2017 BVSTools
GreenBoard(v3) Powered by the eRPG SDK, MAILTOOL Plus!, GreenTools for Google Apps, jQuery, jQuery UI, BlockUI, CKEditor and running on the IBM i (AKA AS/400, iSeries, System i).