C# NetSuite SuiteTalk:SavedSearch搜索;“已删除记录”;类型

C# NetSuite SuiteTalk:SavedSearch搜索;“已删除记录”;类型,c#,web-services,soap,netsuite,suitetalk,C#,Web Services,Soap,Netsuite,Suitetalk,如何在NetSuite中获得“已删除记录”类型的“已保存搜索”的结果?其他搜索类型很明显(CustomerSearchAdvanced、ItemSearchAdvanced等),但这一种似乎没有在线参考,只是文档,没有在其上运行保存的搜索 更新1 我应该进一步澄清一下我想做什么。在NetSuite中,您可以对记录类型“Deleted record”运行(并保存)保存的搜索,我相信您可以通过此过程从web界面访问至少5列(不包括用户定义的列): 删除日期 被删除 上下文 记录类型 名字 您还可

如何在NetSuite中获得“已删除记录”类型的“已保存搜索”的结果?其他搜索类型很明显(CustomerSearchAdvanced、ItemSearchAdvanced等),但这一种似乎没有在线参考,只是文档,没有在其上运行保存的搜索

更新1

我应该进一步澄清一下我想做什么。在NetSuite中,您可以对记录类型“Deleted record”运行(并保存)保存的搜索,我相信您可以通过此过程从web界面访问至少5列(不包括用户定义的列):

  • 删除日期
  • 被删除
  • 上下文
  • 记录类型
  • 名字

您还可以将搜索条件设置为“已保存搜索”的一部分。我想访问一系列这些“已保存的搜索”已在我的系统中使用其已设置的搜索条件,并从所有5个显示列中检索数据。

自2016年版起,SuiteTalk不支持删除的记录记录,这意味着您无法运行已保存的搜索并下拉结果

这在与NetSuite集成时并不少见:(

在这种情况下,我通常会创建一个RESTlet(NetSuite想要的RESTful API框架)SuiteScript来运行搜索(或者使用SuiteScript执行任何可能的操作,而使用SuiteTalk执行任何不可能的操作)并返回结果

从文件中:

您可以部署与NetSuite数据交互的服务器端脚本 遵循RESTful原则。RESTlet将SuiteScript API扩展到 允许与NetSuite进行自定义集成。使用 RESTlet包括以下功能:

通过以下方式找到提高可用性和性能的机会 实现更轻量级、更安全的RESTful集成 比基于SOAP的web服务更灵活。支持无状态通信 在客户端和服务器之间。控制客户端和服务器的实现。 在中使用基于令牌或用户凭据的内置身份验证 HTTP头。在iPhone和iPhone等平台上开发移动客户端 集成外部基于Web的应用程序,如Gmail或 谷歌应用。为基于Suitelet的用户界面创建后端。 RESTlet为熟悉 SuiteScript比NetSuite基于SOAP的web支持更多的行为 服务,仅限于定义为SuiteTalk操作的服务。 restlet也比Suitelets更安全,后者是可用的 对于未登录的用户。有关更详细的比较,请参阅RESTlet 与其他NetSuite集成选项相比

在您的情况下,这将是一个几乎不需要创建的脚本,它将收集结果并返回JSON编码(最简单)或任何您需要的格式

与编写脚本相比,您可能要花费更多的时间来实现基于令牌的身份验证(TBA)

[Update]添加一些与我在下面评论中提到的内容相关的代码示例:

请注意,SuiteTalk代理对象模型令人沮丧,因为它 缺乏继承性,它可以很好地利用。所以你以 像SafeTypeCastName()这样的代码。反射是最好的工具之一 在我的工具箱中,当涉及到使用SuiteTalk代理时 例如,所有*RecordRef类型都有公共字段/道具,因此反射 保存您在整个位置进行的类型检查,以便使用您要创建的对象 我怀疑你有

公共静态TType GetProperty(对象记录,字符串propertyID)
{
PropertyInfo pi=record.GetType().GetProperty(propertyID);
返回(TType)pi.GetValue(记录,空);
}
公共静态字符串GetInternalID(记录)
{
返回GetProperty(记录“internalId”);
}
公共静态字符串GetInternalID(BaseRef recordRef)
{
PropertyInfo pi=recordRef.GetType().GetProperty(“internalId”);
返回(字符串)pi.GetValue(recordRef,null);
}
公共静态CustomFieldRef[]GetCustomFieldList(记录)
{
返回GetProperty(记录,CustomFieldPropertyName);
}

自2016\u 2版起,SuiteTalk不支持
已删除记录
记录,这意味着您无法运行已保存的搜索并下拉结果

这在与NetSuite集成时并不少见:(

在这种情况下,我通常会创建一个RESTlet(NetSuite想要的RESTful API框架)SuiteScript来运行搜索(或者使用SuiteScript执行任何可能的操作,而使用SuiteTalk执行任何不可能的操作)并返回结果

从文件中:

您可以部署与NetSuite数据交互的服务器端脚本 遵循RESTful原则。RESTlet将SuiteScript API扩展到 允许与NetSuite进行自定义集成。使用 RESTlet包括以下功能:

通过以下方式找到提高可用性和性能的机会 实现更轻量级、更安全的RESTful集成 比基于SOAP的web服务更灵活。支持无状态通信 在客户端和服务器之间。控制客户端和服务器的实现。 在中使用基于令牌或用户凭据的内置身份验证 HTTP头。在iPhone和iPhone等平台上开发移动客户端 集成外部基于Web的应用程序,如Gmail或 谷歌应用。为基于Suitelet的用户界面创建后端。 RESTlet为熟悉 SuiteScript比NetSuite基于SOAP的web支持更多的行为 服务,仅限于定义为SuiteTalk操作的服务。 restlet也比Suitelets更安全,后者是可用的 对于未登录的用户。有关更详细的比较,请参阅RESTlet 与其他NetSuite集成选项相比

在您的情况下,这将是一个几乎微不足道的脚本来创建,它将收集
public static TType GetProperty<TType>(object record, string propertyID)
{
    PropertyInfo pi = record.GetType().GetProperty(propertyID);
    return (TType)pi.GetValue(record, null);
}

public static string GetInternalID(Record record)
{
    return GetProperty<string>(record, "internalId");
}

public static string GetInternalID(BaseRef recordRef)
{
    PropertyInfo pi = recordRef.GetType().GetProperty("internalId");
    return (string)pi.GetValue(recordRef, null);
}

public static CustomFieldRef[] GetCustomFieldList(Record record)
{
    return GetProperty<CustomFieldRef[]>(record, CustomFieldPropertyName);
}
//private NetSuiteService nsService = new DataCenterAwareNetSuiteService("login");
//private TokenPassport createTokenPassport() { ... }

private IEnumerable<DeletedRecord> DeletedRecordSearch()
{
    List<DeletedRecord> results = new List<DeletedRecord>();
    int totalPages = Int32.MaxValue;
    int currentPage = 1;

    while (currentPage <= totalPages)
    {
        //You may need to reauthenticate here
        nsService.tokenPassport = createTokenPassport();

        var queryResults = nsService.getDeleted(new GetDeletedFilter
        {
            //Add any filters here...
            //Example
            /*
            deletedDate = new SearchDateField()
                    {
                        @operator = SearchDateFieldOperator.after,
                        operatorSpecified = true,
                        searchValue = DateTime.Now.AddDays(-49),
                        searchValueSpecified = true,
                        predefinedSearchValueSpecified = false,
                        searchValue2Specified = false
                    }
            */
        }, currentPage);

        currentPage++;
        totalPages = queryResults.totalPages;

        results.AddRange(queryResults.deletedRecordList);
    }

    return results;
}

private Tuple<string, string> SafeTypeCastName(
    Dictionary<string, string> customList, 
    BaseRef input)
{
    if (input.GetType() == typeof(RecordRef)) {
        return new Tuple<string, string>(((RecordRef)input).name, 
            ((RecordRef)input).type.ToString());
    }
    //Not sure why "Last Sales Activity Record" doesn't return a type...
    else if (input.GetType() == typeof(CustomRecordRef)) {
        return new Tuple<string, string>(((CustomRecordRef)input).name, 
            customList.ContainsKey(((CustomRecordRef)input).internalId) ? 
                customList[((CustomRecordRef)input).internalId] : 
                "Last Sales Activity Record"));
    }
    else {
        return new Tuple<string, string>("", "");
    }
}

public Dictionary<string, string> GetListCustomTypeName()
{
    //You may need to reauthenticate here
    nsService.tokenPassport = createTokenPassport();

    return
        nsService.search(new CustomListSearch())
            .recordList.Select(a => (CustomList)a)
            .ToDictionary(a => a.internalId, a => a.name);
}

//Main code starts here
var results = DeletedRecordSearch();
var customList = GetListCustomTypeName();

var demoResults = results.Select(a => new
{
    DeletedDate = a.deletedDate,
    Type = SafeTypeCastName(customList, a.record).Item2,
    Name = SafeTypeCastName(customList, a.record).Item1
}).ToList();