Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Trying to get NetSuite Country list with enumeration value linked to code and name

Tags:

c#

netsuite

I am implementing a integration with NetSuite in C#. In the external system I need to populate a list of countries that will match NetSuite's country list.

The NetSuite Web Service provides an enumeration call Country

public enum Country {
  _afghanistan,
  _alandIslands,
  _albania,
  _algeria,
  ...

You can also get a list of country Name and Code (in an albeit not so straight forward way) from the web service. (See: http://suiteweekly.com/2015/07/netsuite-get-all-country-list/)

Which gives you access to values like this:

  • Afghanistan, AF
  • Aland Islands, AX
  • Albania, AL
  • Algeria, DZ
  • American Samoa, AS
  • ...

But, as you can see, there is no way to link the two together. (I tried to match by index but that didn't work and sounds scary anyway)

NetSuite's "help" files have a list. But this is static and I really want a dynamic solution that updates as NetSuites updates because we know countries will change--even is not that often.

Screenshot of Country Enumerations from NetSuite help docs

The only solutions I have found online are people who have provided static data that maps the two sets of data. (ex. suiteweekly.com /2015/07/netsuite-complete-country-list-in-netsuite/)

I cannot (don't want to) believe that this is the only solution.

Anyone else have experience with this that has a better solution?

NetSuite, if you are reading, come on guys, give a programmer a break.

like image 408
Andrew Hawes Avatar asked Oct 28 '25 16:10

Andrew Hawes


1 Answers

The best solution I have come up with is to leverage the apparent relationship between the country name and the enumeration key to forge a link between the two. I am sure others could improve on this solution but what I would really like to see is a solution that isn't a hack like this that relies on an apparent pattern but rather on that is based on an explicit connection. Or better yet NetSuite should just provide the data in one place all together.

For example you can see the apparent relationship here:

_alandIslands -> Aland Islands

With a little code I can try to forge a match.

I first get the Enumeration Keys into an array. And I create a list of objects of type NetSuiteCountry that will hold my results.

var countryEnumKeys = Enum.GetNames(typeof(Country));
var countries = new List<NetSuiteCountry>();

I then loop through the list of country Name and Code I got using the referenced code above (not shown here).

For each country name I then strip all non-word characters from the country name with Regex.Replace, prepend an underscore (_) and then convert the string to lowercase. Finally I try to find a match between the Enumeration Key (converted to lowercase as well) and the matcher string that was created. If a match is found I save all the data together the countries list.

UPDATE: Based on the comments I have added additional code/hacks to try to deal with the anomalies without hard-coding exceptions. Hopefully these updates will catch any future updates to the country list as well, but no promises. As of this writing it was able to handle all the known anomalies. In my case I needed to ignore Deprecated countries so those aren't included.

foreach (RecordRef baseRef in baseRefList)
{
  var name = baseRef.name;

  //Skip Deprecated countries
  if (name.EndsWith("(Deprecated)")) continue;

  //Use the name to try to find and enumkey match and only add a country if found.
  var enumMatcher = $"_{Regex.Replace(name, @"\W", "").ToLower()}";

  //Compares Ignoring Case and Diacritic characters
  var enumMatch = CountryEnumKeys.FirstOrDefault(e => string.Compare(e, enumMatcher, CultureInfo.CurrentCulture, CompareOptions.IgnoreNonSpace | CompareOptions.IgnoreCase) == 0);

  //Then try by Enum starts with Name but only one.
  if (enumMatch == null)
  {
    var matches = CountryEnumKeys.Where(e => e.ToLower().StartsWith(enumMatcher));
    if (matches.Count() == 1)
    {
      Debug.Write($"- Country Match Hack 1 : ");
      enumMatch = matches.First();
    }
  }

  //Then try by Name starts with Enum but only one.
  if (enumMatch == null)
  {
    var matches = CountryEnumKeys.Where(e => enumMatcher.StartsWith(e.ToLower()));
    if (matches.Count() == 1)
    {
      Debug.Write($"- Country Match Hack 2 : ");
      enumMatch = matches.First();
    }
  }

  //Finally try by first half Enum and Name match but again only one.
  if (enumMatch == null)
  {
    var matches = CountryEnumKeys.Where(e => e.ToLower().StartsWith(enumMatcher.Substring(0, (enumMatcher.Length/2))));
    if (matches.Count() == 1)
    {
      Debug.Write($"- Country Match Hack 3 : ");
      enumMatch = matches.First();
    }
  }

  if (enumMatch != null)
  {
    var enumIndex = Array.IndexOf(CountryEnumKeys, enumMatch);
    if (enumIndex >= 0)
    {
      var country = (Country) enumIndex;
      var nsCountry = new NetSuiteCountry
      {
        Name = baseRef.name,
        Code = baseRef.internalId,
        EnumKey = country.ToString(),
        Country = country
      };

      Debug.WriteLine($"[{nsCountry.Name}] as [{nsCountry.EnumKey}]");
      countries.Add(nsCountry);
    }
  }
  else
  {
    Debug.WriteLine($"Could not find Country match for: [{name}] as [{enumMatcher}]");
  }
}

Here is my NetSuiteCountry class:

public class NetSuiteCountry
{
    public string Name { get; set; }
    public string Code { get; set; }
    public string EnumKey { get; set; }
    public Country Country { get; set; }
}
like image 197
Andrew Hawes Avatar answered Oct 31 '25 06:10

Andrew Hawes