Using Flex2Crystal in Web Apps

The same basic steps used to add Flex2Crystal to a Windows app are required to use Flex2Crystal in a web app as well. But web apps present some unique challenges related to returning the output of the report to the browser. Because DataFlex includes a newer “Web App Framework” and an older “Classic Web App” model, included are examples of how to use Flex2Crystal in each case.

Web Application Framework

The following example shows how to migrate the DataFlex 18.2 CustomerListSample.wo in the WebOrder workspace to the latest version of Crystal Reports. The original version of this wo simply returned a static PDF file. We’ll use it as a shell to show how to run a Flex2Crystal report that generates a PDF and return that PDF.

Add the Flex2Crystal Library to Your Workspace

  1. Start DataFlex Studio and open the required workspace.

  2. Select Tools ‣ Maintain Libraries from the DataFlex menu bar. Existing library paths (if any) are displayed in the Library Maintenance dialog box.

  3. Click Add Library.

  4. Navigate to the User Documents\Mertech Data Systems\Flex2Crystal\lib folder.

  5. Select Flex2Crystal.sws, then click Open.

  6. A confirmation dialog box prompts to add the library using relative pathing (Yes) or absolute pathing (No). It is recommended that you select Yes. The Library Maintenance dialog box shows the addition of the Flex2Crystal library.

../../_images/library.png
  1. Click OK.

Update the .wo File

Edit the CustomerListSample.wo to use the cFlex2Crystal.pkg and to define an output filename property.

Use cWebView.pkg
Use cWebPanel.pkg
Use cWebForm.pkg
Use cWebRadio.pkg
Use cWebCheckbox.pkg
Use cWebForm.pkg
Use cWebButton.pkg
Use cWebLabel.pkg
Use cWebGroup.pkg

// Add the cFlex2Crystal.pkg
Use cFlex2Crystal.pkg

// Modify the caption and add variable psOutFileName
Object oCustomerListSample is a cWebView
   Set piWidth to 700
   Set psCaption to "Customer List (Crystal Report)"
   Property String psOutputFileName ""

Modify the RunReport procedure to use the newly defined output filename and to run the Crystal Object (oCrystalRpt) RunReport method. If the report (PDF file) is successfully generated, it is displayed in a new browser tab.

Replace the Report object (oReport) with the Crystal Object (oCrystalRpt) shown below. oCrystalRpt selects the report to be run, sets up the selection criteria and runs the report. It includes the OnExport procedure that writes the report (PDF file) to the folder assigned by the DataFlex framework. A random function is used to ensure the report filename is unique.

   Procedure RunReport
      String sUrl

      // Use the new variable psOutFileName
      Set psOutputFileName  to ""
      Send RunReport of oCrystalRpt

      If ((psOutputFileName(Self))="") Begin
         Send ShowInfoBox "The Report could not be generated"
      End
      Else Begin
         Get DownloadURL of ghoWebResourceManager (psOutputFileName(Self)) to sUrl

         // this is used to show a PDF file in a new browser tab or window
         // use btNewTab to open a new browser tab page
         // use btNewWindow to open a new browser window
         Send NavigateToPage sUrl btNewTab

         // this is used to show a PDF file in an embedded viewer within this view
         // WebSet psUrl of oWebIFrame1 to sUrl
      End
   End_Procedure

   // Replaces oReport in the original wo
   Object oCrystalRpt is a cFlex2Crystal

      Set psReportName to "customerswithgooglemap18.rpt"
      Set peOutputDestination to PRINT_TO_FILE

      Procedure OnInitializeReport Handle hoReport
         Integer[] iCustomerCustomerNumbers
         String[] sCustomerNames
         String sSelection
         Handle hoParam
         Integer iRadio iSortDirection
         Boolean bAscending

         Forward Send OnInitializeReport hoReport

         // customer number filter
         WebGet psValue of oFromCustomerCustomerNumber to iCustomerCustomerNumbers[0]
         WebGet psValue of oToCustomerCustomerNumber to iCustomerCustomerNumbers[1]

         If (iCustomerCustomerNumbers[0] <> 0) Begin
            Append sSelection "{Customer.Customer_Number} >= " iCustomerCustomerNumbers[0]
         End

         If (iCustomerCustomerNumbers[1] <> 0) Begin
            Append sSelection (If(sSelection<>"", " and ", "")) "{Customer.Customer_Number} <= " iCustomerCustomerNumbers[1]
         End

         // customer name filter
         WebGet psValue of oFromCustomerName to sCustomerNames[0]
         WebGet psValue of oToCustomerName to sCustomerNames[1]

         If (sCustomerNames[0] <> "") Begin
            Append sSelection (If(sSelection<>"", " and ", ""))  "{Customer.Name} >= " '"' (Trim(sCustomerNames[0])) '"'
         End

         If (sCustomerNames[1] <> "") Begin
            Append sSelection (If(sSelection<>"", " and ", "")) "{Customer.Name} <= " '"' (Trim(sCustomerNames[1])) '"'
         End

         // sorting
         WebGet psValue of oSortNumber to iRadio
         Get GetChecked of oSortAscending to bAscending

         // Delete old sort order
         Send DeleteSortOrder of hoReport

         // Setup new sort order
         Move (If(bAscending,crAscendingOrder, crDescendingOrder)) to iSortDirection

         If (iRadio=0) Send AppendSortField of hoReport "Customer" "Customer_Number" iSortDirection
         Else Send AppendSortField of hoReport "Customer" "Name" iSortDirection


         // Send the selection criteria to the report
         Set ComRecordSelectionFormula of hoReport to sSelection

         Get GetParamObjectByName of hoReport "SelTxt" to hoParam
         If (hoParam) Send ComAddCurrentValue of hoParam sSelection
      End_Procedure

      // Place the report in the folder that the framework has assigned.
      // Use the Random function to ensure a unique filename
      Procedure OnExportReport Handle hoReport
         Handle hoExport
         String sFile sUrl

         Set pbExportPrompt of hoReport to False

         Forward Send OnExportReport hoReport
         Get ExportObject of hoReport to hoExport
            If (hoExport) Begin

               Get GetReportsCache of ghoWebApp True to sFile
               Move (sFile + "\customerlist" + String(Random(1000000000)) + ".pdf") to sFile

               Set ComDestinationType of hoExport to crEDTDiskFile
               Set ComDiskFileName of hoExport to  sFile
               Set pbCanceled of hoExport to False
               Set ComFormatType of hoExport to crEFTPortableDocFormat // PDF
               Set psOutputFileName to sFile
            End
      End_Procedure // OnExportReport

   End_Object //oCrystalRpt

End_Object // oCustomerListSample

Do the Cleanup

This example generates a PDF report stored in a folder assigned by the DataFlex framework. At some point old reports have to be removed from disk. You may want to write a cleanup procedure to do this.

Report Features

The report itself, customerswithgooglemap18.rpt, demonstrates some noteworthy features available in Crystal Reports.

  • How to embed a Google map in a report

  • The Use of SQL Expression fields

../../_images/web-order.png

Classic Web Application

Any Web app not using the Web Application Framework is referred to as a classic web application. Published functions are called from ASP or directly from the browser using SOAP or JSON. The following example shows how to update the DataFlex 15.1 Order Entry workspace to work with the latest version of Crystal Reports.

Add the Flex2Crystal Library to Your Workspace

You can follow the procedures shown in the previous example (Add the Flex2Crystal Library to Your Workspace) or you can copy the library file to the OrderEntry\AppSrc directory.

Create a CrystalReport.wo

This sample wo contains two report objects. Each report object defines the report to be run, selection parameters and print to file option. Each report object also contain the OnExportReport procedure that writes the report to disk in PDF format. The filename is defined in the WebBusinessProcess object, which runs the selected report.

Note

You can define as many reports as you want in one wo and then use it to serve all your reporting needs.

Use cWebBusinessProcess.pkg
Use cFlex2Crystal.pkg


// First Report
Object oCrystalRpt is a cFlex2Crystal
   Set psReportName to "customers.rpt"
   Property String psExportFileName ""

   Set peOutputDestination to PRINT_TO_FILE

   Procedure OnInitializeReport Handle hoReport
      Forward Send OnInitializeReport hoReport
      Handle hoParam

      Get GetParamObjectByName of hoReport "SelTxt" to hoParam
      If (hoParam) Send ComAddCurrentValue of hoParam "CA"
   End_Procedure

   //Set the output path and output file format (PDF) and write the file to disk
   Procedure OnExportReport Handle hoReport
      Handle hoExport

      Set pbExportPrompt of hoReport to False

      Forward Send OnExportReport hoReport

      Get ExportObject of hoReport to hoExport
         If (hoExport) Begin
            Set ComDestinationType  of hoExport to crEDTDiskFile

            Set ComDiskFileName of hoExport to (psExportFileName(Self))
            Set ComFormatType of hoExport to crEFTPortableDocFormat // PDF
         End
      End_Procedure // OnExportReport
End_Object

// Second Report, similar to the first report but with additional selection criteria
Object oCrystalRptWithParams is a cFlex2Crystal

   Set psReportName to "customers.rpt"
   Set peOutputDestination to PRINT_TO_FILE

   Property String  psExportFileName ""
   Property Integer piFromCustomerCustomerNumber
   Property Integer piToCustomerCustomerNumber
   Property Integer piIndex

   Procedure OnInitializeReport Handle hoReport
      String sSelection
      Handle hoParam
      Integer iRadio iSortDirection
      Boolean bAscending

      Forward Send OnInitializeReport hoReport

      If (piFromCustomerCustomerNumber(Self) <> 0) Begin
         Append sSelection "{Customer.Customer_Number} >= " (piFromCustomerCustomerNumber(Self))
      End

      If (piToCustomerCustomerNumber(Self) <> 0) Begin
         Append sSelection (If(sSelection<>"", " and ", "")) "{Customer.Customer_Number} <= " (piToCustomerCustomerNumber(Self))
      End

      // Delete old sort order
      Send DeleteSortOrder of hoReport

      If (piIndex(Self)=1) Send AppendSortField of hoReport "Customer" "Customer_Number" crAscendingOrder
      Else Send AppendSortField of hoReport "Customer" "Name" crAscendingOrder


      Set ComRecordSelectionFormula of hoReport to sSelection

      Get GetParamObjectByName of hoReport "SelTxt" to hoParam
      If (hoParam) Send ComAddCurrentValue of hoParam "CA"
   End_Procedure

   //Set the output path and output file format (PDF) and write the file to disk
   Procedure OnExportReport Handle hoReport
      Handle hoExport

      Set pbExportPrompt of hoReport to False

      Forward Send OnExportReport hoReport

      Get ExportObject of hoReport to hoExport
      If (hoExport) Begin
         Set ComDestinationType  of hoExport to crEDTDiskFile

         Set ComDiskFileName of hoExport to (psExportFileName(Self))
         Set ComFormatType of hoExport to crEFTPortableDocFormat // PDF
      End
   End_Procedure // OnExportReport

End_Object

// WebBusinessProcess: Contains two published functions, one to run each report. Both generate a random filename so existing report files are not overwritten.
Object oCrystalReport is a cWebBusinessProcess
   Set psDescription to "Crystal Report"

   { Published = True  }
   { Description = ""  }
   Function RunReport  Returns String
      String sFile
      Move ("\customerlist" + String(Random(1000000000)) + ".pdf") to sFile

      Set psExportFileName    of oCrystalRpt to  ((psAppHtmlPath(phoWorkspace(oApplication))) - sFile)
      Send RunReport          of oCrystalRpt
      Function_Return sFile
   End_Function

   { Published = True  }
   { Description = ""  }
   Function RunReportWithParams Integer iFromCustomerNo Integer iToCustomerNo Integer iIndex Returns String
      String sFile
      Move ("\customerlist" + String(Random(1000000000)) + ".pdf") to sFile

      Set piFromCustomerCustomerNumber    of oCrystalRptWithParams to iFromCustomerNo
      Set piToCustomerCustomerNumber      of oCrystalRptWithParams to iToCustomerNo
      Set piIndex                         of oCrystalRptWithParams to iIndex
      Set psExportFileName                of oCrystalRptWithParams to ((psAppHtmlPath(phoWorkspace(oApplication))) - sFile)
      Send RunReport                      of oCrystalRptWithParams
      Function_Return sFile
   End_Function
End_Object

Let the Browser Open the Report

This example uses ASP to call the report and get back the path to the generated PDF. The ASP code then redirects the browser to this file.

<h3>Customer Information Drill Down Report</h3>

<%
    Index      = request("Index")           ' The last selected Index number
    SelStart1  = request("SelStart1")
    SelStop1   = request("SelStop1")

    sFile = oCrystalReport.call("get_RunReportWithParams", SelStart1, SelStop1, Index )
    Response.Redirect(sFile)

%>

Do the Cleanup

This example generates a PDF report stored in a folder assigned by the DataFlex framework. At some point old reports have to be removed from disk. You may want to write a cleanup procedure to do this.