Passing data from a Business Portal Result Viewer Web Part to Dynamics GP Web Services

Chris Roehrich

This post will provide some steps on using the MBF Result Viewer API to pass data to the Dynamics GP Web Services.    The specific example shows how you can remove a line item from a Sales Order using the UpdateSalesOrder method.   The sales order number, line sequence number, and item number can be pulled off the Rich List Result Viewer web part and passed to the web services. 

The Result Viewer API is discussed in the BPIntegrationGuide.pdf file on the Business Portal 3.0 CD and also available on MSDN.  The first step is to use a handwritten htm file that will render the Rich List result viewer in a Page Viewer web part.   The htm file will also include a button in the task area of the web part.   The button event will open a custom ASPX page and provides the sales order line item data using QueryString parameters.  

The following is a screen shot of the finished web part and the code in the htm file:

Rich List Result Viewer

Code Example

<%@ page language="C#" autoeventwireup="true" inherits="LineItems, App_Web_zymlzqk_" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html XMLNS:RL>
 <head runat =server>
  <?IMPORT namespace="RL" implementation="/BusinessPortal/UI/ResultViewer/Scripts/Rich.htc"/>
  <title>Rich List</title>
  <script>
   function OnRichList16Ready()
   {
    //Add a stylesheet.
    RichList16.AddStyleSheet("/BusinessPortal/UI/ResultViewer/Stylesheets/RichList.css");
    
    //Add a button
    var button = RichList16.ActionButtons.AddButton();
    button.ButtonValue = "Remove Line";
    button.ButtonTitle = "Click to remove selected line item.";
    button.OnAction = RemoveLineItem;    

   }
   function RemoveLineItem()
   {
    if (RichList16.API.SelectedRow == -1)
    {
     alert("A sales document must be selected.");
    }
    else
    {
     var sFeatures = "scrollbars=yes,resizable=yes,height=600px,width=800px,status=yes";     
     var theWindow = window.open('/BusinessPortal/Applications/SalesDocIntegration/UpdateSalesDoc.aspx?SalesDocumentID='
      + RichList16.API.Key(RichList16.API.SelectedRow, 0) + '&LineSeqNumber='
       + RichList16.API.Key(RichList16.API.SelectedRow, 2) + '&ItemNumber='
       + RichList16.API.GetValue(RichList16.API.SelectedRow, 1), null, sFeatures); 
     
     RichList16.API.Refresh();
    }
   }
  </script> 
 </head>
 <body style="margin:0">
  <RL:Rich
  id="RichList16"  
  SupportsAutoRefresh="true"
  EventNameSpace="Microsoft.Dynamics.SalesOrder.Transaction.SalesDocument"  
  AutoRefresh="1"
  SupportsPageSize="true"
  PageSize="25"
  HasFind="true"
  HasHeader="true"
  HasActionButtons="true"  
  QueryServiceURL="/BusinessPortal/QueryWebService.asmx?WSDL"
  InitialQuery="/DataViewer/Sales Document Integration/Line Items Per Sales Document"
  UseLegacySubscribe="true" 
  OnReady="OnRichList16Ready()"
  />
 </body>
</html>

In the window.open method, a URL to the UpdateSalesDoc.aspx page is passed along with the SalesDocumentID, LineSeqNumber, and ItemNumber parameters.   To retrieve these data values from the selected row in the web part, there is one property and two methods of the Result Viewer API that are used that I will further explain below.

The SelectedRow property returns the zero-based index of the currently selected row of the web part.  So if you are on the third row of the web part it will return a 2.   The first row would return a 0.

The Key method takes a int value that represents the row and another int value that represents the segment of the key.  It returns the value of the key segment in the query specified by the zero-based row and key index.  In the code example, the query is using the Sales Document entity.   The Sales Document entity key is made up of the Document Number for the first segment and Document Type for the second segment.   Additionally, the Sales Document Line details are being pulled in the query so the third segment of the key is the Line Sequence Number.

The GetValue method takes a int value that represents the row and another int value that represents the column.  It returns the value of the cell in the grid specified by the zero-based row and column.  In the code example, I am passing a 1 for the column value since the Item Number is the second column in the query.

I will move on to using the Web Services for Dynamics GP to update the Sales Order where the selected line item is removed.   It is important to follow the white paper steps for the building and configuration of the .Net application in Business Portal and to leverage session information like the current company I am logged into in Business Portal.  I will provide the code below that takes the document number, line sequence number, and item number values from the query string to the UpdateSalesOrder method call:  

Code Example

using System;
using System.Collections;
using System.Configuration;
using System.Data;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;

using DynamicsGPService;
using System.Web.Services.Protocols;
using Microsoft.BusinessFramework;
using Microsoft.BusinessFramework.Entity;

public partial class UpdateSalesDoc : System.Web.UI.Page
{

    protected void Page_Load(object sender, EventArgs e)
    {
        this.docNumberLabel.Text = Request.QueryString["SalesDocumentID"];
        this.lineSeqLabel.Text = Request.QueryString["LineSeqNumber"];
        this.segmentsLabel.Text = Request.QueryString["KeySegments"];
        this.itemLabel.Text = Request.QueryString["ItemNumber"];
    }
    protected void Button1_Click(object sender, EventArgs e)
    {
        Response.Write("<script>window.close()</script>");
       
    }
    protected void deleteButton_Click(object sender, EventArgs e)
    {
        CompanyKey companyKey;
        Context context;
        SalesDocumentKey salesOrderKey;
        SalesOrder salesOrder;
        SalesOrderLine salesOrderLine;
        Policy salesOrderUpdatePolicy;

        // Create an instance of the web service
        DynamicsGP wsDynamicsGP = new DynamicsGP();

        // Be sure the default credentials are used
        wsDynamicsGP.UseDefaultCredentials = true;

        // Create a context with which to call the web service
        context = new Context();

        // Specify which company to use (sample company)
        companyKey = new CompanyKey();
        companyKey.Id = this.GetDBID();

        // Set up the context object
        context.OrganizationKey = (OrganizationKey)companyKey;
        context.CultureName = "en-US";

        // Create a sales document key
        salesOrderKey = new SalesDocumentKey();
        salesOrderKey.Id = this.docNumberLabel.Text;

        try
        {

            // Retrieve the sales order
            salesOrder = wsDynamicsGP.GetSalesOrderByKey(salesOrderKey, context);

            // Create the line ItemKey

            ItemKey itemKey = new ItemKey();
            itemKey.Id = this.itemLabel.Text;

            // Create the line for removal
            salesOrderLine = new SalesOrderLine();
            salesOrderLine.Key = new SalesLineKey();
            salesOrderLine.Key.LineSequenceNumber = Convert.ToInt32(this.lineSeqLabel.Text);
            salesOrderLine.Key.SalesDocumentKey = salesOrderKey;
            salesOrderLine.DeleteOnUpdate = true;
            salesOrderLine.ItemKey = itemKey;

            // Create an array of sales order lines
            // Initialize the array with the sales order line object
            SalesOrderLine[] lineToRemove = { salesOrderLine };

            // Add the sales order line array to the sales line object
            salesOrder.Lines = lineToRemove;

            // Retrieve the update policy for sales orders
            salesOrderUpdatePolicy = wsDynamicsGP.GetPolicyByOperation("UpdateSalesOrder", context);

            // Update the sales order object
            wsDynamicsGP.UpdateSalesOrder(salesOrder, context, salesOrderUpdatePolicy);

            statusLabel.Text = "Line removed successfully!";

        }

        catch (SoapException se)
        {
            statusLabel.Text = se.Message + se.StackTrace;

        }

        catch (Exception ex1)
        {
            statusLabel.Text = ex1.Message + ex1.StackTrace;

        }       

    }

    public int GetDBID()
    {
        int dbID;
        EntityKey eK;
        eK = (Microsoft.Dynamics.Common.Company.Company.Key)EnterpriseSession.DefaultParentKey;
        Microsoft.Dynamics.Common.Company.Company company = (Microsoft.Dynamics.Common.Company.Company)eK.GetEntity();
        dbID = company.ID;
        return dbID;
    }
}

 

The salesOrderLine.DeleteOnUpdate property is set to true and the salesOrder.Lines array is set to just the line we are attempting to remove.   Doing this will allow the web services to create eConnect XML where just the SOP Header node (taSopHdrIvcInsert) and the SOP Line Delete node (taSopLineDelete) are passed to the eConnect API.  

 

Hopefully this post can provide some helpful information for folks that would like to leverage Business Portal data as a launch pad for integrating web service calls.

 

Chris

// Copyright © Microsoft Corporation. All Rights Reserved.
// This code released under the terms of the
// Microsoft Public License (MS-PL, https://opensource.org/licenses/ms-pl.html.)