通过RESTful API获取Acumatica中的联系人

问题描述 投票:0回答:2

@ HB_ACUMATICA,等,

在过去的几个月里,我一直在努力将客户的FileMaker数据库与Acumatica集成。我能够访问(获取/放置)各种表(实体),例如PROJECT和CUSTOMER,但CONTACT实体总是产生错误。例如,

https://mydomain.acumatica.com/entity/Default/18.200.001/Customer [工作正常]

https://mydomain.acumatica.com/entity/Default/18.200.001/Contact [总是错误500]

** [编辑:上述示例当然是不完整的,除非试图找到'所有'联系人记录。在测试中,我指定了实际的联系人ID,如,

https://mydomain.acumatica.com/entity/Default/18.200.001/Customer/Nobody

“没有人”是真正的联系人ID ...或者我被引导相信...请参阅下面的答案] **

我在文档中查看过,它表示“联系人”是实体的正确名称。我究竟做错了什么?

非常感谢。 - 埃里克

acumatica filemaker
2个回答
1
投票

这是一个尚未修复的已知问题。 Web服务调用返回的错误消息是:

{
    "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字段(这似乎不适用于来自默认端点的字段,仅用于自定义字段):enter image description here

使用该方法,您必须将URL中的端点更改为扩展端点名称(在此示例中为“DefaultPlus”):

https://mydomain.acumatica.com/entity/DefaultPlus/18.200.001/Contact

0
投票

WRONG: Data Field is 'Display Name' — 'ContactID' is 102155, not 'Wegweiser, Erik'

啊哈!谢谢,所有这些都可能是有用的信息,可能会派上用场。然而,这些问题以及我对没有正确做事的担忧被证明是“红色鲱鱼”。再一次,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”,并且根据惯例,合理地将其视为唯一标识符,实际上是明确命名的“DisplayName”。正如人们所期望的那样,真正的“ContactID”是真正的唯一ID。

Acumatica是一个奇妙的工具。它只是一种真正不同的动物,有许多头(或者有些可能是尾巴),iMHO。


由HB_ACUMATICA编辑

Contact.ContactID DAC中查看Contact字段定义它确实被声明为Integer字段,并且没有自定义属性可以在屏幕上返回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图,它使用Contact.ContactID机制重新定义CacheAttached 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 DAC中不存在的Contact属性。快速浏览一下这个属性就会发现它正在使用DescriptionPXSelector字段在屏幕上显示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值。

© www.soinside.com 2019 - 2024. All rights reserved.