C# SuiteTalk Advanced Search Example

I’ve come back to this same sample code several times when writing a SuiteTalk advanced search. The last time I wrote one, I thought I’d make some improvements. Needless to say, it didn’t go well. Let me explain.

First! This example is using a standard user account to authenticate. See my other blog posts regarding how to use token-based authentication when you do this for real.

Next, make sure you add web services to your role. Otherwise, you can’t connect. I forgot this when I was doing some testing, bouncing back and forth between roles. That set me back, dang it!

Security Settings

Here’s my gotcha… I decided when coding up columns, I didn’t need to fill an empty array with an empty object (as you’ll see below). However, when you omit the empty object, the API returns results, but the results are empty! So I’d get back my quote and line items. In this case, I’d get a searchRowList with 5 rows. But the rows had nothing in them. TransactionSearchRowBasic was all nulls, as was ItemSearchRowBasic. All nulls! This sent me down a bad debugging path, thinking I had a security issue.

Main

Since WordPress doesn’t do a very good job of formatting code, I’ll share a few screenshots of the remainder of my code. Then I’ll include the code so you can cut and paste.

FetchEstimates

One more…

ProcessTransactions

And one more… This class sets your web services’ URL based on your account.

DataCenterAwareNetSuiteService

And here’s the code:

using System;
using System.IO;
using System.Data;
using System.Data.SqlClient;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net;
using Newtonsoft.Json;
using SuiteTalkImports.nsWS;

class getQuoteAdvSearch
{

private const string account = “[your account number here]”;

static void Main(string[] args)
{
NetSuiteService service = CommonCode.InitService();
Passport passport = CommonCode.InitPassport();
Status status = service.login(passport).status;

TransactionSearchAdvanced advanced = new TransactionSearchAdvanced()
{
columns = new TransactionSearchRow()
{
basic = new TransactionSearchRowBasic()
{
internalId = new SearchColumnSelectField[] { new SearchColumnSelectField() },
tranId = new SearchColumnStringField[] { new SearchColumnStringField() },
externalId = new SearchColumnSelectField[] { new SearchColumnSelectField() },
title = new SearchColumnStringField[] { new SearchColumnStringField() },
createdBy = new SearchColumnSelectField[] { }
},
itemJoin = new ItemSearchRowBasic()
{
externalId = new SearchColumnSelectField[] { new SearchColumnSelectField() },
displayName = new SearchColumnStringField[] { new SearchColumnStringField() },
type = new SearchColumnEnumSelectField[] { new SearchColumnEnumSelectField() },
subType = new SearchColumnEnumSelectField[] { new SearchColumnEnumSelectField() },
basePrice = new SearchColumnDoubleField[] { new SearchColumnDoubleField() },
cost = new SearchColumnDoubleField[] { new SearchColumnDoubleField() }
}

},
criteria = new TransactionSearch()
{
basic = new TransactionSearchBasic()
{
tranId = new SearchStringField()
{
@operator = SearchStringFieldOperator.@is,
operatorSpecified = true,
searchValue = “[Your quote number here]”
}
}
}
};

FetchEstimates(service, advanced);

service.logout();
Console.ReadLine();
}

private static void FetchEstimates(NetSuiteService service, object TransactionSearchObject)
{
Console.WriteLine(“Getting Datacenter URL from NetSuite”);
service.Timeout = 1000 * 60 * 60 * 2;

SearchPreferences savePreferences = service.searchPreferences;

service.searchPreferences = new SearchPreferences()
{
bodyFieldsOnly = false,
returnSearchColumns = true
};
Console.WriteLine(“Downloading Estimates from NetSuite”);

SearchResult result = service.search(TransactionSearchObject as TransactionSearchAdvanced);

if (result.status.isSuccess)
{
ProcessTransactionSearchRows(result);
}
else
{
Console.WriteLine(“”);
foreach (StatusDetail detail in result.status.statusDetail)
{
Console.WriteLine(detail.message);
}
}

service.searchPreferences = savePreferences;
}

private static void ProcessTransactionSearchRows(SearchResult result)
{
Console.WriteLine($”Results: {result.searchRowList.Length}”);
List<Estimate> estimates = new List<Estimate>();

foreach (TransactionSearchRow row in result.searchRowList)
{
TransactionSearchRowBasic basic = row.basic;
ItemSearchRowBasic itemBasic = row.itemJoin;
Estimate Found = estimates.Find(p => p.internalId == basic.internalId[0].searchValue.internalId);

if (Found == null)
{
string internalId = “”;
try { internalId = basic.internalId[0].searchValue.internalId; } catch { }

string externalId = “”;
try { externalId = basic.externalId[0].searchValue.externalId; } catch { }

string tranId = “”;
try { tranId = basic.tranId[0].searchValue; } catch { }

string title = “”;
try { title = basic.title[0].searchValue; } catch { }

string createdBy = “”;
try { createdBy = basic.createdBy[0].searchValue.name; } catch { }

Estimate estimate =
new Estimate()
{
internalId = internalId,
tranId = tranId,
externalId = externalId,
title = title
};

estimates.Add(estimate);

Console.WriteLine(“Estimate: ” + estimate.tranId);
}
else
{
Console.WriteLine(“Line Item: ” + itemBasic.displayName[0].searchValue);
}
}
}
}
class DataCenterAwareNetSuiteService : NetSuiteService
{
public DataCenterAwareNetSuiteService(string account)
: base()
{
System.Uri originalUri = new System.Uri(this.Url);
DataCenterUrls urls = getDataCenterUrls(account).dataCenterUrls;
Uri dataCenterUri = new Uri(urls.webservicesDomain + originalUri.PathAndQuery);
this.Url = dataCenterUri.ToString();
}
}

Leave a comment