Organization Details
Overview
A report that uses Ajax to list the customers in an organization tree and load a customer's various details on demand, such as a volume snapshot, recent orders, and current autoships.
Namespaces
This sample requires the following namespaces:
using ExigoOData; using ExigoWebService;
Exigo API Authentication
This sample accesses the web service using the ExigoApi object:
public ExigoApi Exigo { get { return new ExigoApi { ApiAuthenticationValue = new ApiAuthentication { LoginName = exigoAPILoginName, Password = exigoAPIPassword, Company = exigoAPICompany } }; } }
This sample also accesses OData using the ExigoContext object:
public ExigoContext ExigoOData { get { var context = new ExigoOData.ExigoContext(new Uri("http://api.exigo.com/4.0/" + exigoAPICompany + "/model")); context.IgnoreMissingProperties = true; var credentials = Convert.ToBase64String(Encoding.ASCII.GetBytes(exigoAPILoginName + ":" + exigoAPIPassword)); context.SendingRequest += (object s, SendingRequestEventArgs e) => e.RequestHeaders.Add("Authorization", "Basic " + credentials); return context; } }
jQuery
We use jQuery for easier Ajax calls and theming. We are also using an autocomplete plugin for our search.
<link href="<%=this.ResolveUrl("Assets/Styles/OrganizationDetailReport.css") %>" rel="stylesheet" type="text/css" /> <link href="<%=this.ResolveUrl("../../Themes/start/jquery-ui.custom.css") %>" rel="stylesheet" type="text/css" /> <script src="<%=this.ResolveUrl("../../Scripts/jquery.min.js") %>" type="text/javascript"></script> <script src="<%=this.ResolveUrl("../../Scripts/jquery-ui.min.js") %>" type="text/javascript"></script> <script src="<%=this.ResolveUrl("Assets/Plugins/Autocomplete.js") %>" type="text/javascript"></script>
Fetching Downline Nodes
To fetch downline nodes from the enroller tree, we use the OData's EnrollerTree query. We are not using the EnrollerTreePeriodVolumes query because we don't need any volume information. We are also passing in an int variable called "page", which represents the pagination of the infinite scrolling feature in the downline navigation pane.
return (from n in ExigoOData.EnrollerTree where n.TopCustomerID == enrollerID select new EnrollerNode() { CustomerID = n.CustomerID, Customer = n.Customer, Level = n.Level }).Skip((page - 1) * 50).Take(50).ToList();
Fetching Customer Summary
To fetch a customer's summary, we use the Customers OData query:
return (from c in ExigoOData.Customers where c.CustomerID == customerID select new Customer() { CustomerID = c.CustomerID, FirstName = c.FirstName, LastName = c.LastName }).FirstOrDefault();
Fetching Customer Wall
To fetch a customer's wall, we use the CustomerWall OData query:
return (from c in ExigoOData.CustomerWall where c.CustomerID == customerID orderby c.WallItemID descending select new WallItem() { CustomerID = c.CustomerID, EntryDate = c.EntryDate, Text = c.Text, Field1 = c.Field1, Field2 = c.Field2 }).Take(maxWallItemsCount).ToList();
Fetching Order History
To fetch a customer's order history, we use the Orders OData query:
return (from o in ExigoOData.Orders where o.CustomerID == customerID orderby o.OrderDate descending select new Order() { OrderID = o.OrderID, OrderDate = o.OrderDate, Total = o.Total, BusinessVolumeTotal = o.BusinessVolumeTotal, CommissionableVolumeTotal = o.CommissionableVolumeTotal, OrderStatus = o.OrderStatus, Details = o.Details }).Take(maxRecentOrdersCount).ToList();
Fetching Autoships
To fetch a customer's autoships, we use the AutoOrders OData query:
return (from o in ExigoOData.AutoOrders where o.CustomerID == customerID where o.AutoOrderStatusID == 0 orderby o.NextRunDate descending select new AutoOrder() { FrequencyType = o.FrequencyType, LastRunDate = o.LastRunDate, NextRunDate = o.NextRunDate, Total = o.Total, BusinessVolumeTotal = o.BusinessVolumeTotal, CommissionableVolumeTotal = o.CommissionableVolumeTotal, Details = o.Details }).Take(maxAutoshipsCount).ToList();
Rendering The Report
Whenever we want to request a section of the report, including when the page loads, we use jQuery's AJAX function to call the current page while passing in two query string parameters, called "datakey" and any other query string parameters the section requires.
$.ajax({ url: 'OrganizationDetailReport.aspx?datakey=' + dataKey + '&' + query, cache: false, success: function (data) { $(selector).html(data); if(endFunction) { endFunction(selector, data); } }, error: function (data, status, error) { alert('error: ' + error); }, dataType: "html" });
On the server-side, we have overridden the Page's Render method to handle page requests differently if the query string parameter "datakey" exists.
protected override void Render(HtmlTextWriter writer) { if (Request.QueryString["datakey"] != null) { Response.Clear(); int id = Convert.ToInt32(Request.QueryString["id"]); int page = Convert.ToInt32(Request.QueryString["page"]); switch (Request.QueryString["datakey"]) { case "downlinelist": RenderDownlineList(writer, id, page); break; case "search": string filter = Request.QueryString["filter"]; RenderSearchResults(writer, filter, page); break; case "summary": RenderCustomerSummary(writer, id); break; case "orders": RenderRecentOrders(writer, id); break; case "autoships": RenderAutoships(writer, id); break; case "wall": RenderCustomerWall(writer, id); break; default: return; } Response.End(); } else { base.Render(writer); } }