Acumatica API:使用.ActionConvertToAccount转换Lead失败

Acumatica API:使用.ActionConvertToAccount转换Lead失败,acumatica,Acumatica,我正在尝试使用Acumatica API(版本4.20.2231)作为Lead屏幕,将Lead转换为业务帐户。在我尝试之前,我就有点担心这个问题,因为当你在Acumatica中使用“转换为商业帐户”操作时,它会弹出一个小对话框。以下是选择操作>转换为业务帐户后Acumatica中的外观: 对于API,我尝试的第一种命令安排是无法转换Lead,并且不会产生任何错误。最后,我发现了一系列命令,这些命令产生了一个引用对话框的错误,这让我觉得我走对了方向。也许我只是不知道如何使用命令操纵对话框。有人知

我正在尝试使用Acumatica API(版本4.20.2231)作为Lead屏幕,将Lead转换为业务帐户。在我尝试之前,我就有点担心这个问题,因为当你在Acumatica中使用“转换为商业帐户”操作时,它会弹出一个小对话框。以下是选择操作>转换为业务帐户后Acumatica中的外观:

对于API,我尝试的第一种命令安排是无法转换Lead,并且不会产生任何错误。最后,我发现了一系列命令,这些命令产生了一个引用对话框的错误,这让我觉得我走对了方向。也许我只是不知道如何使用命令操纵对话框。有人知道我哪里出错了吗?这是我的密码:

Public Function ConvertLeadToCustomer(ByVal leadID As String, ByVal firstName As String, ByVal lastName As String, ByRef companyName As String) As String
    Dim CR301000 As CR301000Content = m_context.CR301000GetSchema()
    m_context.CR301000Clear()

    ' converting a lead requires that there is a value for company, so create one if it is blank
    If companyName = "" Then
        companyName = lastName & ", " & firstName
    End If

    ' create key field
    Dim leadKeyValue As Value = New Value With {.LinkedCommand = CR301000.LeadSummary.LeadID, .Value = leadID}

    ' create company field, since its required
    Dim companyValue As Value = New Value With {.LinkedCommand = CR301000.DetailsSummary.CompanyName, .Value = companyName, .Commit = True}

    Dim updateLeadCommands As Command() = {leadKeyValue, CR301000.Actions.ActionConvertToBAccount, companyValue, CR301000.Actions.Save}
    Dim updateLeadResult As CR301000Content() = m_context.CR301000Submit(updateLeadCommands)

    ' TO DO: search Business Accounts by name to find new Business Account ID
    Dim newBAID As String = ""
    Return newBAID 
End Function
以下是调用CR301000Submit时返回的错误:

System.Web.Services.Protocols.SoapException: Server was unable to process request. ---> PX.Data.PXDialogRequiredException
    at PX.Data.DialogManager.a(String A_0, PXGraph A_1, String A_2, Object A_3, String A_4, String A_5, MessageButtons A_6, MessageIcon A_7, Boolean A_8, InitializePanel A_9)
    at PX.Data.DialogManager.AskExt(PXView view, String key, InitializePanel initializeHandler, Boolean repaintControls)
    at PX.Data.PXView.AskExt(InitializePanel initializeHandler, Boolean refreshRequired)
    at PX.Objects.CR.LeadMaint.ConvertToBAccount(PXAdapter adapter)
    at PX.Data.PXAction`1.a(PXAdapter A_0)
    at PX.Data.PXAction`1.<Press>d__c.MoveNext()
    at PX.Data.PXAction`1.<Press>d__c.MoveNext()
    at PX.Data.PXAction`1.<Press>d__c.MoveNext()
    at PX.Data.PXAction`1.<Press>d__c.MoveNext()
    at PX.Api.SyImportProcessor.SyStep.CommitChanges(Object itemToBypass, PXFilterRow[] targetConditions)
    at PX.Api.SyImportProcessor.ExportTableHelper.ExportTable()
    at PX.Api.ScreenUtils.Submit(String screenId, Command[] commands, SchemaMode schemaMode, PXGraph graph)
    at PX.Api.Services.ScreenService.Submit(String id, IEnumerable`1 commands, SchemaMode schemaMode)
    at PX.Api.Soap.Screen.ScreenGate.Submit(Command[] commands)
--- End of inner exception stack trace --- 
System.Web.Services.Protocols.SoapException:服务器无法处理请求。-->PX.Data.PXDialogRequiredException
在PX.Data.DialogManager.a(字符串a_0、PXGraph a_1、字符串a_2、对象a_3、字符串a_4、字符串a_5、消息按钮a_6、消息图标a_7、布尔值a_8、初始化名称a_9)
在PX.Data.DialogManager.AskExt(PXView视图、字符串键、InitializePanel initializeHandler、布尔重绘控件)
在PX.Data.PXView.AskExt(InitializePanel initializeHandler,需要布尔刷新)
在PX.Objects.CR.LeadMaint.ConvertToAccount(PXAdapter适配器)上
在PX.Data.PXAction`1.a处(PXAdapter a_0)
在PX.Data.PXAction`1.d_uc.MoveNext()中
在PX.Data.PXAction`1.d_uc.MoveNext()中
在PX.Data.PXAction`1.d_uc.MoveNext()中
在PX.Data.PXAction`1.d_uc.MoveNext()中
在PX.Api.SyImportProcessor.SyStep.CommitChanges(对象项ToByPass,PXFilterRow[]targetConditions)
在PX.Api.SyImportProcessor.ExportTableHelper.ExportTable()处
在PX.Api.ScreenUtils.Submit(stringscreenid,Command[]commands,SchemaMode-SchemaMode,PXGraph-graph)
在PX.Api.Services.ScreenService.Submit(字符串id,IEnumerable`1命令,SchemaMode SchemaMode)
在PX.Api.Soap.Screen.ScreenGate.Submit(Command[]commands)
---内部异常堆栈跟踪结束--

指定的命令应用于对话框,而不是摘要。 在调用操作之前,应提供必需的字段和对话框答案

下面是用于在收据屏幕中创建收据操作的示例。 注:C#代码


希望这有帮助。

您当前的问题

发生错误的原因是操作
ConvertToBAccount
正在调用一个弹出对话框,并希望得到一个答案:

if (AccountInfo.AskExt((graph, view) => graph.Views[view].Cache.Clear(), true) != WebDialogResult.OK) return contacts;
告诉Acumatica答案的方法是在调用动作之前发送值“OK”。根据您的配置,您可能还希望填充此弹出窗口中的字段:

Dim commandsConvert As Command() =
    {
        New Value With {.Value = leadID, .LinkedCommand = CR301000.LeadSummary.LeadID, .Commit = True},
        New Value With {.Value = "OK", .LinkedCommand = CR301000.NewAccountServicesSettings.ServiceCommands.DialogAnswer, .Commit = True}, 'This is how close the pop-up. We fill the field from the pop-up after this line
        New Value With {.Value = newCompanyCD, .LinkedCommand = CR301000.NewAccountServicesSettings.BAccountID}, 'With autonumbering On, no need for this line.
        New Value With {.Value = newCompanyName, .LinkedCommand = CR301000.NewAccountServicesSettings.AccountName}, 'The default value will be taken from DetailsSummary.CompanyName
        CR301000.Actions.ActionConvertToBAccount
    }

m_context.CR301000Submit(commandsConvert)
你未来的问题

从Lead转换为BAccount是一个两步过程,您将被重定向到新创建的BAccount并需要保存它。只要不保存它,它就不会被转换

这通常是一个非常直接的过程,或者您只需将
Save
提交到重定向页面(CR303000):

只要您保持相同的cookie容器,
UserState
就应该知道您当前使用的是脏的CR303000,其中包含缓存的信息。如果您使用同时包含CR301000和CR303000的自定义web服务端点,则无需处理任何问题

不幸的是,在这种情况下,它不起作用

似乎
PXRedirectRequiredException
是从
PXLongOperation
(读取线程)中引发的,并且Web服务没有选择BAccount的脏状态。我现在能找到的唯一解决方案是自定义操作
convertToAccount
以删除线程:

public class LeadMaintExt : PXGraphExtension<LeadMaint>
{
    [PXUIField(DisplayName = Messages.ConvertToBAccount, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
    [PXButton(ImageKey = PX.Web.UI.Sprite.Main.Process)]
    public virtual IEnumerable ConvertToBAccount(PXAdapter adapter)
    {
        List<Contact> contacts = new List<Contact>(adapter.Get().Cast<Contact>());
        foreach (Contact lead in contacts)
        {
            if (Base.AccountInfo.AskExt((graph, view) => graph.Views[view].Cache.Clear(), true) != WebDialogResult.OK) return contacts;
            bool empty_required = !Base.AccountInfo.VerifyRequired();
            BAccount existing = PXSelect<BAccount, Where<BAccount.acctCD, Equal<Required<BAccount.acctCD>>>>.SelectSingleBound(Base, null, Base.AccountInfo.Current.BAccountID);
            if (existing != null)
            {
                Base.AccountInfo.Cache.RaiseExceptionHandling<LeadMaint.AccountsFilter.bAccountID>(Base.AccountInfo.Current, Base.AccountInfo.Current.BAccountID, new PXSetPropertyException(Messages.BAccountAlreadyExists, Base.AccountInfo.Current.BAccountID));
                return contacts;
            }
            if (empty_required) return contacts;

            Base.Save.Press();
            //PXLongOperation.StartOperation(this, () => ConvertToAccount(lead, AccountInfo.Current));
            LeadMaint.ConvertToAccount(lead, Base.AccountInfo.Current);
        }
        return contacts;
    }
}
公共类LeadMaintExt:PXGrapherExtension
{
[PXUIField(DisplayName=Messages.ConvertToAccount,MapEnableRights=PXCacheRights.Update,MapViewRights=PXCacheRights.Select)]
[PXButton(ImageKey=PX.Web.UI.Sprite.Main.Process)]
公共虚拟IEnumerable ConvertToAccount(PXAdapter适配器)
{
列表联系人=新列表(adapter.Get().Cast());
foreach(触点中的触点引线)
{
如果(Base.AccountInfo.AskExt((图形,视图)=>graph.Views[view].Cache.Clear(),true)!=WebDialogResult.OK)返回联系人;
bool empty_required=!Base.AccountInfo.VerifyRequired();
BAccount existing=PXSelect.SelectSingleBound(Base,null,Base.AccountInfo.Current.BAccountID);
if(现有!=null)
{
Base.AccountInfo.Cache.RaiseExceptionHandling(Base.AccountInfo.Current,Base.AccountInfo.Current.BAccountID,新PXSetPropertyException(Messages.BAccountAlreadyExists,Base.AccountInfo.Current.BAccountID));
返回联系人;
}
如果(需要清空)返回触点;
Base.Save.Press();
//PXLongOperation.StartOperation(此,()=>转换为Account(lead,AccountInfo.Current));
LeadMaint.ConvertToAccount(lead、Base.AccountInfo.Current);
}
返回联系人;
}
}

我正在寻找一种更好的方法来解决这个问题,找到答案后我会编辑我的答案。

我认为您为该对话框设置了错误的链接命令。在提供的示例中,您正在设置“CR301000.LeadSummary.LeadID”的值,该值不是弹出窗口。在调用ActionConvertToAccount之前,为弹出窗口设置信息并为创建按钮添加命令感谢@Philippe给出的第一个答案以及对第二个问题的预测和进一步研究。是的,如果你找到另一个解决方案,请让我知道。嗨,菲利普,我们还没有定制,但是我们正在升级到5.20.2067建立。这个问题在5.20.2067版本中修复了吗?如果没有,那么我们
'Once the Process is completed, We want to save the new record.
'If we want to edit some information on the new Business Account
'this is the right place to do it.

Dim newBAID As String = String.Empty
Dim commandsBAccount As Command() =
    {
        CR303000.Actions.Save,
        CR303000.AccountSummary.BusinessAccount
    }
Dim newBAccountContent As CR303000Content() = m_context.CR303000Submit(commandsBAccount)
If newBAccountContent.Length > 0 Then
    newBAID = newBAccountContent(0).AccountSummary.BusinessAccount.Value
End If
public class LeadMaintExt : PXGraphExtension<LeadMaint>
{
    [PXUIField(DisplayName = Messages.ConvertToBAccount, MapEnableRights = PXCacheRights.Update, MapViewRights = PXCacheRights.Select)]
    [PXButton(ImageKey = PX.Web.UI.Sprite.Main.Process)]
    public virtual IEnumerable ConvertToBAccount(PXAdapter adapter)
    {
        List<Contact> contacts = new List<Contact>(adapter.Get().Cast<Contact>());
        foreach (Contact lead in contacts)
        {
            if (Base.AccountInfo.AskExt((graph, view) => graph.Views[view].Cache.Clear(), true) != WebDialogResult.OK) return contacts;
            bool empty_required = !Base.AccountInfo.VerifyRequired();
            BAccount existing = PXSelect<BAccount, Where<BAccount.acctCD, Equal<Required<BAccount.acctCD>>>>.SelectSingleBound(Base, null, Base.AccountInfo.Current.BAccountID);
            if (existing != null)
            {
                Base.AccountInfo.Cache.RaiseExceptionHandling<LeadMaint.AccountsFilter.bAccountID>(Base.AccountInfo.Current, Base.AccountInfo.Current.BAccountID, new PXSetPropertyException(Messages.BAccountAlreadyExists, Base.AccountInfo.Current.BAccountID));
                return contacts;
            }
            if (empty_required) return contacts;

            Base.Save.Press();
            //PXLongOperation.StartOperation(this, () => ConvertToAccount(lead, AccountInfo.Current));
            LeadMaint.ConvertToAccount(lead, Base.AccountInfo.Current);
        }
        return contacts;
    }
}