通过 RESTful API 在 Acumatica 中获取联系人
Get Contact(s) in Acumatica via RESTful API
@HB_ACUMATICA、等
过去几个月我一直致力于将客户的 FileMaker 数据库与 Acumatica 集成。我能够访问 (get/put) 各种表(实体),例如 PROJECT 和 CUSTOMER,但 CONTACT 实体总是会产生错误。例如,
https://mydomain.acumatica.com/entity/Default/18.200.001/Customer
[工作正常]
https://mydomain.acumatica.com/entity/Default/18.200.001/Contact
[总是报错500]
**[编辑:上面的例子当然是不完整的,除非试图找到 'all' 联系人记录。在测试中,我指定了实际的联系人 ID,如
https://mydomain.acumatica.com/entity/Default/18.200.001/Customer/Nobody
其中 'Nobody' 是一个真实的联系人 ID...或者让我相信...请参阅下面的回答]**
我在文档中到处查看,它表明 "Contact" 是实体的正确名称。我做错了什么?
非常感谢。
-- 埃里克
这是一个尚未修复的已知问题。网络服务调用返回的错误信息是:
{
"message": "An error has occurred.",
"exceptionMessage": "Optimization cannot be performed.The following fields cause the error:\r\nAddressValidated: View AddressCurrent has BQL delegate\r\n",
"exceptionType": "PX.Api.ContractBased.OptimizedExport.CannotOptimizeException",
"stackTrace": " at PX.Api.ContractBased.OptimizedExport.NotWorkingOptimizedExportProvider.get_CanOptimize() in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\OptimizedExport\NotWorkingOptimizedExportProvider.cs:line 84\r\n at PX.Api.ContractBased.EntityService.GetList(ISystemContract systemContract, String version, String name, EntityImpl entity, Boolean returnFullEntities, CbOperationContext operationContext, Boolean ignoreValueFields, PXGraph graph) in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\EntityService.cs:line 116\r\n at PX.Api.ContractBased.Soap.SoapFacadeBase.GetListImpl(Entity entity, Boolean returnFullEntities) in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\Soap\SoapFacadeBase.cs:line 83\r\n at PX.Api.ContractBased.SystemContracts.V2.RestController.GetList(String objectName, String select, String filter, String expand, String custom, Nullable`1 skip, Nullable`1 top) in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\SystemContracts\V2\RestController.cs:line 247\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
获取字段AddressValidated
时出现错误。但是,请求甚至没有返回该字段。 编辑它仅在激活地址验证功能时返回
作为解决方法,我所做的是通过 ContactID 获取单个联系人,然后复制返回的所有字段名称。然后我将这些字段放在请求的 select
子句中,该子句指定应返回哪个字段。这似乎具有不涉及 AddressValidated
的副作用并且调用成功:
https://mydomain.acumatica.com/entity/Default/18.200.001/?$select=Active,AddressIsSameAsInAccount,BusinessAccount,CompanyName,ContactClass,ContactID,ContactMethod,ConvertedBy,DateOfBirth,DisplayName,DoNotCall,DoNotEmail,DoNotFax,DoNotMail,Duplicate,DuplicateFound,Email,Fax,FaxType,FirstName,Gender,Image,JobTitle,LanguageOrLocale,LastIncomingActivity,LastName,LastOutgoingActivity,MaritalStatus,MiddleName,NoMarketing,NoMassMail,Owner,OwnerEmployeeName,ParentAccount,Phone1,Phone1Type,Phone2,Phone2Type,Phone3,Phone3Type,QualificationDate,Reason,Source,SourceCampaign,SpouseOrPartnerName,Status,Synchronize,Title,Type,WebSite,Workgroup,WorkgroupDescription
正如 Samvel Petrosov 提到的,您还可以扩展端点并从那里删除 AddressValidated
字段(这似乎不适用于来自默认端点的字段,仅用于自定义字段):
使用这种方法,您必须将 URL 中的端点更改为扩展端点名称(本例中为 'DefaultPlus'):
https://mydomain.acumatica.com/entity/DefaultPlus/18.200.001/Contact
WRONG: Data Field is 'Display Name' — 'ContactID' is 102155, not 'Wegweiser, Erik'
啊哈!谢谢大家提供的可能有用的信息,这些信息可能会派上用场。然而,这些问题和我对没有正确做某事的担忧结果证明是 'red herrings.' 再一次,Acumatica 在遵循自己的惯例方面奇怪的不一致让我感到困惑。
我试图以与 elsewhwere 相同的格式执行请求,例如
https://mydomain.acumatica.com/entity/Default/18.200.001/Customer/ACME001
(其中 'ACME001' 是真实的客户 ID),工作正常,一切正常。然而,
https://mydomain.acumatica.com/entity/Default/18.200.001/Contact/Nobody
(其中 'Nobody' 是真实的联系人 ID)不起作用。
为什么?尽管我持怀疑态度并做出更好的判断,但 30 年的数据库编程经验告诉我,Acumatica 的 'ContactID' 不是唯一记录标识符的明智实现……我相信别人告诉我的。就在元素属性检查器中,它说标记为 "Contact ID" 的字段的真实名称确实是 'ContactID.'
当我最终尝试另一种形式的查询时,
https://mydomain.acumatica.com/entity/Default/18.200.001/Contact?$filter=LastName eq 'Wegweiser'&$select=FirstName,ContactID
我终于收到了向我展示真相的有效载荷:
不幸的是,在别处被标识为 'ContactID' 并且根据惯例合理地被视为唯一标识符的实际上是 sensibly-named 'DisplayName.'
真正的 'ContactID,' 正如人们所期望的那样,是真正的唯一 ID。
Acumatica 是一个奇妙的工具。恕我直言,这只是一种真正不同的动物,有很多头(或者有些可能是尾巴)。
编辑 HB_ACUMATICA
查看 Contact
DAC 中的 Contact.ContactID
字段定义,它确实被声明为 Integer
字段并且没有自定义属性 return String
屏幕显示值:
#region ContactID
public abstract class contactID : IBqlField { }
[PXDBIdentity(IsKey = true)]
[PXUIField(DisplayName = "Contact ID", Visibility = PXUIVisibility.Invisible)]
[PXPersonalDataWarning]
public virtual Int32? ContactID { get; set; }
#endregion
仅凭此 DAC 定义,屏幕上显示的字段是 String
类型而不是 Integer
确实不连贯。对此行为的解释是 Contact Screen
使用 ContactMaint
图,它使用 CacheAttached
机制重新定义 Contact.ContactID
DAC 字段:
[PXUIField(DisplayName = "Contact ID")]
[ContactSelector(true, typeof(ContactTypesAttribute.person), typeof(ContactTypesAttribute.employee))]
[PXMergeAttributes(Method = MergeMethod.Merge)]
public virtual void Contact_ContactID_CacheAttached(PXCache sender) { }
请注意,Contact.ContactID
字段重新定义添加了一个 ContactSelector
属性,该属性在 Contact
DAC 中不存在。快速查看该属性会发现它正在使用 PXSelector
的 Description
字段在屏幕上显示 DisplayName
字符串而不是 Integer
值。此替换仅用于在绑定到 ContactMaint
图形的屏幕中显示目的,所有数据库操作仍然基于 Integer
。 ContactSelector 摘录:
public ContactSelectorAttribute(bool showContactsWithNullEmail, params Type[] contactTypes)
: base(GetQuery(typeof(Contact.contactID), showContactsWithNullEmail, contactTypes))
{
if (contactTypes == null || contactTypes.Length == 0)
throw new ArgumentNullException(nameof(contactTypes));
DescriptionField = typeof(Contact.displayName);
}
REST Web 服务调用未使用 Contact
DAC 而不是 ContactMaint
图表,这就是它需要 Integer
而不是 String
值的原因。
@HB_ACUMATICA、等
过去几个月我一直致力于将客户的 FileMaker 数据库与 Acumatica 集成。我能够访问 (get/put) 各种表(实体),例如 PROJECT 和 CUSTOMER,但 CONTACT 实体总是会产生错误。例如,
https://mydomain.acumatica.com/entity/Default/18.200.001/Customer
[工作正常]
https://mydomain.acumatica.com/entity/Default/18.200.001/Contact
[总是报错500]
**[编辑:上面的例子当然是不完整的,除非试图找到 'all' 联系人记录。在测试中,我指定了实际的联系人 ID,如
https://mydomain.acumatica.com/entity/Default/18.200.001/Customer/Nobody
其中 'Nobody' 是一个真实的联系人 ID...或者让我相信...请参阅下面的回答]**
我在文档中到处查看,它表明 "Contact" 是实体的正确名称。我做错了什么?
非常感谢。 -- 埃里克
这是一个尚未修复的已知问题。网络服务调用返回的错误信息是:
{
"message": "An error has occurred.",
"exceptionMessage": "Optimization cannot be performed.The following fields cause the error:\r\nAddressValidated: View AddressCurrent has BQL delegate\r\n",
"exceptionType": "PX.Api.ContractBased.OptimizedExport.CannotOptimizeException",
"stackTrace": " at PX.Api.ContractBased.OptimizedExport.NotWorkingOptimizedExportProvider.get_CanOptimize() in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\OptimizedExport\NotWorkingOptimizedExportProvider.cs:line 84\r\n at PX.Api.ContractBased.EntityService.GetList(ISystemContract systemContract, String version, String name, EntityImpl entity, Boolean returnFullEntities, CbOperationContext operationContext, Boolean ignoreValueFields, PXGraph graph) in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\EntityService.cs:line 116\r\n at PX.Api.ContractBased.Soap.SoapFacadeBase.GetListImpl(Entity entity, Boolean returnFullEntities) in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\Soap\SoapFacadeBase.cs:line 83\r\n at PX.Api.ContractBased.SystemContracts.V2.RestController.GetList(String objectName, String select, String filter, String expand, String custom, Nullable`1 skip, Nullable`1 top) in C:\Bld2\AC-FULL2017R21-JOB1\sources\NetTools\PX.Api.ContractBased\SystemContracts\V2\RestController.cs:line 247\r\n at lambda_method(Closure , Object , Object[] )\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ActionExecutor.<>c__DisplayClass10.<GetExecutor>b__9(Object instance, Object[] methodParameters)\r\n at System.Web.Http.Controllers.ReflectedHttpActionDescriptor.ExecuteAsync(HttpControllerContext controllerContext, IDictionary`2 arguments, CancellationToken cancellationToken)\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ApiControllerActionInvoker.<InvokeActionAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Filters.ActionFilterAttribute.<CallOnActionExecutedAsync>d__5.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.ActionFilterAttribute.<ExecuteActionFilterAsyncCore>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ActionFilterResult.<ExecuteAsync>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Filters.AuthorizationFilterAttribute.<ExecuteAuthorizationFilterAsyncCore>d__2.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Web.Http.Controllers.ExceptionFilterResult.<ExecuteAsync>d__0.MoveNext()\r\n--- End of stack trace from previous location where exception was thrown ---\r\n at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()\r\n at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)\r\n at System.Web.Http.Dispatcher.HttpControllerDispatcher.<SendAsync>d__1.MoveNext()"
}
获取字段AddressValidated
时出现错误。但是,请求甚至没有返回该字段。 编辑它仅在激活地址验证功能时返回
作为解决方法,我所做的是通过 ContactID 获取单个联系人,然后复制返回的所有字段名称。然后我将这些字段放在请求的 select
子句中,该子句指定应返回哪个字段。这似乎具有不涉及 AddressValidated
的副作用并且调用成功:
https://mydomain.acumatica.com/entity/Default/18.200.001/?$select=Active,AddressIsSameAsInAccount,BusinessAccount,CompanyName,ContactClass,ContactID,ContactMethod,ConvertedBy,DateOfBirth,DisplayName,DoNotCall,DoNotEmail,DoNotFax,DoNotMail,Duplicate,DuplicateFound,Email,Fax,FaxType,FirstName,Gender,Image,JobTitle,LanguageOrLocale,LastIncomingActivity,LastName,LastOutgoingActivity,MaritalStatus,MiddleName,NoMarketing,NoMassMail,Owner,OwnerEmployeeName,ParentAccount,Phone1,Phone1Type,Phone2,Phone2Type,Phone3,Phone3Type,QualificationDate,Reason,Source,SourceCampaign,SpouseOrPartnerName,Status,Synchronize,Title,Type,WebSite,Workgroup,WorkgroupDescription
正如 Samvel Petrosov 提到的,您还可以扩展端点并从那里删除 AddressValidated
字段(这似乎不适用于来自默认端点的字段,仅用于自定义字段):
使用这种方法,您必须将 URL 中的端点更改为扩展端点名称(本例中为 'DefaultPlus'):
https://mydomain.acumatica.com/entity/DefaultPlus/18.200.001/Contact
WRONG: Data Field is 'Display Name' — 'ContactID' is 102155, not 'Wegweiser, Erik'
啊哈!谢谢大家提供的可能有用的信息,这些信息可能会派上用场。然而,这些问题和我对没有正确做某事的担忧结果证明是 'red herrings.' 再一次,Acumatica 在遵循自己的惯例方面奇怪的不一致让我感到困惑。
我试图以与 elsewhwere 相同的格式执行请求,例如
https://mydomain.acumatica.com/entity/Default/18.200.001/Customer/ACME001
(其中 'ACME001' 是真实的客户 ID),工作正常,一切正常。然而,
https://mydomain.acumatica.com/entity/Default/18.200.001/Contact/Nobody
(其中 'Nobody' 是真实的联系人 ID)不起作用。
为什么?尽管我持怀疑态度并做出更好的判断,但 30 年的数据库编程经验告诉我,Acumatica 的 'ContactID' 不是唯一记录标识符的明智实现……我相信别人告诉我的。就在元素属性检查器中,它说标记为 "Contact ID" 的字段的真实名称确实是 'ContactID.'
当我最终尝试另一种形式的查询时,
https://mydomain.acumatica.com/entity/Default/18.200.001/Contact?$filter=LastName eq 'Wegweiser'&$select=FirstName,ContactID
我终于收到了向我展示真相的有效载荷: 不幸的是,在别处被标识为 'ContactID' 并且根据惯例合理地被视为唯一标识符的实际上是 sensibly-named 'DisplayName.' 真正的 'ContactID,' 正如人们所期望的那样,是真正的唯一 ID。
Acumatica 是一个奇妙的工具。恕我直言,这只是一种真正不同的动物,有很多头(或者有些可能是尾巴)。
编辑 HB_ACUMATICA
查看 Contact
DAC 中的 Contact.ContactID
字段定义,它确实被声明为 Integer
字段并且没有自定义属性 return String
屏幕显示值:
#region ContactID
public abstract class contactID : IBqlField { }
[PXDBIdentity(IsKey = true)]
[PXUIField(DisplayName = "Contact ID", Visibility = PXUIVisibility.Invisible)]
[PXPersonalDataWarning]
public virtual Int32? ContactID { get; set; }
#endregion
仅凭此 DAC 定义,屏幕上显示的字段是 String
类型而不是 Integer
确实不连贯。对此行为的解释是 Contact Screen
使用 ContactMaint
图,它使用 CacheAttached
机制重新定义 Contact.ContactID
DAC 字段:
[PXUIField(DisplayName = "Contact ID")]
[ContactSelector(true, typeof(ContactTypesAttribute.person), typeof(ContactTypesAttribute.employee))]
[PXMergeAttributes(Method = MergeMethod.Merge)]
public virtual void Contact_ContactID_CacheAttached(PXCache sender) { }
请注意,Contact.ContactID
字段重新定义添加了一个 ContactSelector
属性,该属性在 Contact
DAC 中不存在。快速查看该属性会发现它正在使用 PXSelector
的 Description
字段在屏幕上显示 DisplayName
字符串而不是 Integer
值。此替换仅用于在绑定到 ContactMaint
图形的屏幕中显示目的,所有数据库操作仍然基于 Integer
。 ContactSelector 摘录:
public ContactSelectorAttribute(bool showContactsWithNullEmail, params Type[] contactTypes)
: base(GetQuery(typeof(Contact.contactID), showContactsWithNullEmail, contactTypes))
{
if (contactTypes == null || contactTypes.Length == 0)
throw new ArgumentNullException(nameof(contactTypes));
DescriptionField = typeof(Contact.displayName);
}
REST Web 服务调用未使用 Contact
DAC 而不是 ContactMaint
图表,这就是它需要 Integer
而不是 String
值的原因。