尝试获取NetSuite国家/地区列表,其枚举值与代码和名称相关联

时间:2016-05-19 08:49:54

标签: c# netsuite

我正在C#中实现与NetSuite的集成。在外部系统中,我需要填写与NetSuite国家/地区列表相匹配的国家/地区列表。

NetSuite Web服务提供枚举调用Country

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

您还可以从网络服务获取国家/地区名称和代码列表(虽然不是那么直截了当)。 (见:http://suiteweekly.com/2015/07/netsuite-get-all-country-list/

这使您可以访问以下值:

  • 阿富汗,AF
  • 奥兰群岛,AX
  • 阿尔巴尼亚,AL
  • 阿尔及利亚,DZ
  • 美属萨摩亚,AS
  • ...

但是,正如您所看到的,没有办法将两者联系在一起。 (我试图通过索引进行匹配,但这不起作用,无论如何都听起来很可怕)

NetSuite的“帮助”文件有一个列表。但这是静态的,我真的想要一个动态的解决方案,随着NetSuites的更新而更新,因为我们知道国家会发生变化 - 即使不是经常发生变化。

Screenshot of Country Enumerations from NetSuite help docs

我在网上找到的唯一解决方案是提供映射两组数据的静态数据的人。 (例如,suiteweekly.com / 2015/07 / netsuite-complete-country-list-in-netsuite /)

我不能(不想)相信这是唯一的解决方案。

其他人有这方面的经验,有更好的解决方案吗?

NetSuite,如果你正在阅读,那就来吧,让程序员休息一下。

2 个答案:

答案 0 :(得分:2)

我提出的最佳解决方案是利用国家/地区名称和枚举密钥之间的明显关系来建立两者之间的联系。我相信其他人可以改进这个解决方案,但我真正希望看到的是一个不是像这样的黑客攻击依赖于明显的模式而是基于显式连接的解决方案。或者更好的是,NetSuite应该只在一个地方提供数据。

例如,你可以在这里看到明显的关系:

_alandIslands - >奥兰群岛

使用一些代码我可以尝试打造一场比赛。

我首先将Enumeration Keys放入数组中。我创建了一个NetSuiteCountry类型的对象列表,它将保存我的结果。

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

然后我使用上面引用的代码循环遍历国家名称和代码列表(此处未显示)。

对于每个国家/地区名称,我将使用Regex.Replace从国家/地区名称中删除所有非单词字符,在前面添加下划线(_),然后将字符串转换为小写。最后,我尝试在Enumeration Key(也转换为小写)和创建的匹配器字符串之间找到匹配。如果找到匹配项,我将所有数据保存在国家/地区列表中。

更新:根据评论,我添加了额外的代码/黑客,试图在没有硬编码异常的情况下处理异常。希望这些更新能够捕获国家列表的任何未来更新,但没有承诺。在撰写本文时,它能够处理所有已知的异常情况。在我的情况下,我需要忽略不推荐使用的国家,因此不包括这些国家。

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}]");
  }
}

这是我的NetSuiteCountry类:

public class NetSuiteCountry
{
    public string Name { get; set; }
    public string Code { get; set; }
    public string EnumKey { get; set; }
    public Country Country { get; set; }
}

答案 1 :(得分:1)

让我先说一句我不是编码员的免责声明,这是我试图查看C#程序的第一天。

我需要类似的Javascript项目,我需要Netsuite公司名称,代码及其数值的完整列表,在阅读帮助时,似乎唯一的方法是通过webservices。

我从Netsuite和Visual Studio版本下载了webservices的示例应用程序,我能够编辑提供的示例程序,以创建所有国家/地区名称和国家/地区代码的列表(例如加拿大,加拿大)。 / p>

我开始做类似于上一张海报的内容,以获取国家/地区名称列表:

string[] countryList = Enum.GetNames(typeof(Country));
foreach (string s in countryList)
{
    _out.writeLn(s);
}

但我后来摆脱了这个并开始了一项新技术。我创建了一个类似于上一个答案的类:

public class NS_Country
{
    public string countryCode { get; set; }
    public string countryName { get; set; }
    public string countryEnum { get; set; }
    public string countryNumericID { get; set; }
}

以下是获取公司名称,代码和ID列表的新代码。我意识到它不是很有效,就像我之前提到的那样,我不是真正的编码器,这是我第一次使用C#,大量谷歌和切割/粘贴; D。

_out.writeLn("  Attempting to get Country list.");
// Create a list for the NS_Country objects
List<NS_Country> CountryList = new List<NS_Country>();

// Create a new GetSelectValueFieldDescription object to use in a getSelectValue search
GetSelectValueFieldDescription countryDesc = new GetSelectValueFieldDescription();
countryDesc.recordType = RecordType.customer;
countryDesc.recordTypeSpecified = true;
countryDesc.sublist = "addressbooklist";
countryDesc.field = "country";

// Create a GetSelectValueResult object to hold the results of the search
GetSelectValueResult myResult = _service.getSelectValue(countryDesc, 0);
BaseRef[] baseRef = myResult.baseRefList;

foreach (BaseRef nsCountryRef in baseRef)
{
    // Didn't know how to do this more efficiently
    // Get the type for the BaseRef object, get the property for "internalId",
    // then finally get it's value as string and assign it to myCountryCode
    string myCountryCode = nsCountryRef.GetType().GetProperty("internalId").GetValue(nsCountryRef).ToString();

    // Create a new NS_Country object
    NS_Country countryToAdd = new NS_Country
    {
        countryCode = myCountryCode,
        countryName = nsCountryRef.name,
        // Call to a function to get the enum value based on the name
        countryEnum = getCountryEnum(nsCountryRef.name)
    };
    try
    {
        // If the country enum was verified in the Countries enum
        if (!String.IsNullOrEmpty(countryToAdd.countryEnum))
        {
            int countryEnumIndex = (int)Enum.Parse(typeof(Country), countryToAdd.countryEnum);
            Debug.WriteLine("Enum: " + countryToAdd.countryEnum + ", Enum Index: " + countryEnumIndex);
            _out.writeLn("ID: " + countryToAdd.countryCode + ", Name: " + countryToAdd.countryName + ", Enum: " + countryToAdd.countryEnum);
        }
    }
    // There was a problem locating the country enum that was not handled
    catch (Exception ex)
    {
        Debug.WriteLine("Enum: " + countryToAdd.countryEnum + ", Enum Index Not Found");
        _out.writeLn("ID: " + countryToAdd.countryCode + ", Name: " + countryToAdd.countryName + ", Enum: Not Found");
    }
    // Add the countryToAdd object to the CountryList
    CountryList.Add(countryToAdd);
}
// Create a JSON - I need this for my javascript
var javaScriptSerializer = new System.Web.Script.Serialization.JavaScriptSerializer();
string jsonString = javaScriptSerializer.Serialize(CountryList);
Debug.WriteLine(jsonString);

为了获取枚举值,我创建了一个名为getCountryEnum的函数:

static string getCountryEnum(string countryName)
{
    // Create a dictionary for looking up the exceptions that can't be converted
    // Don't know what Netsuite was thinking with these ones ;D
    Dictionary<string, string> dictExceptions = new Dictionary<string, string>()
    {
        {"Congo, Democratic Republic of", "_congoDemocraticPeoplesRepublic"},
        {"Myanmar (Burma)", "_myanmar"},
        {"Wallis and Futuna", "_wallisAndFutunaIslands"}
    };

    // Replace with "'s" in the Country names with "s"
    string countryName2 = Regex.Replace(countryName, @"\'s", "s");
    // Call a function that replaces accented characters with non-accented equivalent
    countryName2 = RemoveDiacritics(countryName2);
    countryName2 = Regex.Replace(countryName2, @"\W", " ");

    string[] separators = {" ","'"}; // "'" required to deal with country names like "Cote d'Ivoire"
    string[] words = countryName2.Split(separators, StringSplitOptions.RemoveEmptyEntries);
    for (var i = 0; i < words.Length; i++)
    {
        string word = words[i];
        if (i == 0)
        {
            words[i] = char.ToLower(word[0]) + word.Substring(1);
        }
        else
        {
            words[i] = char.ToUpper(word[0]) + word.Substring(1);
        }
    }
    string countryEnum2 = "_" + String.Join("", words);

    // return an empty string if the country name contains Deprecated
    bool b = countryName.Contains("Deprecated");
    if (b)
    {
        return String.Empty;
    }
    else
    {
        // test to see if the country name was one of the exceptions
        string test;
        bool isExceptionCountry = dictExceptions.TryGetValue(countryName, out test);
        if (isExceptionCountry == true)
        {
            return dictExceptions[countryName];
        }
        else
        {
            return countryEnum2;
        }
    }
}

在上面我使用了一个函数RemoveDiacritics I found here。我将重新发布下面引用的函数:

static string RemoveDiacritics(string text)
{
    string formD = text.Normalize(NormalizationForm.FormD);
    StringBuilder sb = new StringBuilder();
    foreach (char ch in formD)
    {
        UnicodeCategory uc = CharUnicodeInfo.GetUnicodeCategory(ch);
        if (uc != UnicodeCategory.NonSpacingMark)
        {
            sb.Append(ch);
        }
    }
    return sb.ToString().Normalize(NormalizationForm.FormC);
}

以下是测试您开发的任何解决方案的棘手案例:

// Test tricky names
Debug.WriteLine(getCountryEnum("Curaçao"));
Debug.WriteLine(getCountryEnum("Saint Barthélemy"));
Debug.WriteLine(getCountryEnum("Croatia/Hrvatska"));
Debug.WriteLine(getCountryEnum("Korea, Democratic People's Republic"));
Debug.WriteLine(getCountryEnum("US Minor Outlying Islands"));
Debug.WriteLine(getCountryEnum("Cote d'Ivoire"));
Debug.WriteLine(getCountryEnum("Heard and McDonald Islands"));
// Enums that fail
Debug.WriteLine(getCountryEnum("Congo, Democratic Republic of")); // _congoDemocraticPeoplesRepublic added to exceptions
Debug.WriteLine(getCountryEnum("Myanmar (Burma)")); // _myanmar added to exceptions
Debug.WriteLine(getCountryEnum("Netherlands Antilles (Deprecated)")); // Skip Deprecated
Debug.WriteLine(getCountryEnum("Serbia and Montenegro (Deprecated)")); // Skip Deprecated
Debug.WriteLine(getCountryEnum("Wallis and Futuna")); // _wallisAndFutunaIslands added to exceptions

出于我的目的,我想要一个具有Coutries(Name,Code,Enum,Value)的所有值的JSON对象。我会把它包括在这里以防万一有人在搜索它。当您拥有必须将信息转发到Netsuite在线表单的第三方HTML表单时,数值非常有用。

Here is a link to the JSON object on Pastebin

我对缺乏编程知识的看法(只是真的做了一些javascript),希望这些额外的信息对某人有用。