使用 Acumatica 更新和删除付款方式 API

Updating and Deleting Payment Methods with Acumatica API

感谢 Creating customer payment method with api 上的 post,我能够使用 API 成功创建新的付款方式。但我不知道如何更新或删除现有的付款方式。似乎没有任何类型的关键字段。我已经使用 API 更新和删除了联系人和位置,但联系人有联系人 ID,而位置有位置 ID。似乎没有 PaymentMethodID。我想也许 "Card/Account No." 字段可能起到那样的作用,但我无法做到这一点。而且我注意到我可以保存两种具有相同卡号的付款方式,因此如果无论如何使用该字段,它们都会生成相同的密钥。

这是我尝试更新的代码。它主要是来自我链接到的另一个 post 的 Chris 代码,但试图为更新添加一个额外的关键字段。

Public Function UpdateCreditCard(ByVal customerID As String, ByVal existingAcctNum As String, ByVal paymentMethodCode As String, ByVal CCNum As String, ByVal expiration As String, ByVal nameOnCard As String, ByVal active As Boolean)
    Dim paymentMethod As AR303010Content = m_context.AR303010GetSchema()
    m_context.AR303010Clear()

    ' main level fields
    Dim customerVal As Value = CreateValue(paymentMethod.PaymentMethodSelection.Customer, customerID)
    Dim paymentMethodCodeVal As Value = CreateValue(paymentMethod.PaymentMethodSelection.PaymentMethod, paymentMethodCode)

    ' inner level fields
    Dim ccNumName As Value = CreateValue(paymentMethod.PaymentMethodDetails.Description, "CCDNUM")
    Dim ccNumValue As Value = CreateValue(paymentMethod.PaymentMethodDetails.Value, CCNum, True)

    Dim ccExpName As Value = CreateValue(paymentMethod.PaymentMethodDetails.Description, "EXPDATE")
    Dim ccExpValue As Value = CreateValue(paymentMethod.PaymentMethodDetails.Value, expiration, True)

    Dim ccNameName As Value = CreateValue(paymentMethod.PaymentMethodDetails.Description, "NAMEONCC")
    Dim ccNameValue As Value = CreateValue(paymentMethod.PaymentMethodDetails.Value, nameOnCard, True)

    Dim saveCommands() As Command
    If existingAcctNum = "" Then
        ' new credit card
        saveCommands = {customerVal, paymentMethod.Actions.Insert, paymentMethodCodeVal, ccNumName, ccNumValue, ccExpName, ccExpValue, ccNameName, ccNameValue, paymentMethod.Actions.Save}
    Else
        ' existing credit card, only allow update of Active or expiration based on "description"
        Dim descriptionVal As Value = CreateValue(paymentMethod.PaymentMethodDetails.Description, existingAcctNum)
        Dim activeVal As Value = CreateValue(paymentMethod.PaymentMethodSelection.Active, active.ToString())
        saveCommands = {customerVal, descriptionVal, ccExpName, ccExpValue, activeVal, paymentMethod.Actions.Save}
    End If
    Dim updateResult As AR303010Content() = m_context.AR303010Submit(saveCommands)

    Return ""
End Function

另一个令人困惑的部分是,我真正想让用户更新的两个字段是到期日期,或者卡是否有效。但 Active 标志是可从 Customer 屏幕访问的列表中的字段之一,到期日期是只能从 Payment Method 屏幕访问的字段。如果这是两个不同的 API 调用,那么我是否需要在每个调用中使用不同的键字段?

由于几个不同的原因,此屏幕很难通过 Web 服务使用:

  1. 屏幕上没有显示可用于查找付款方式的唯一密钥。内部键是一个名为 PMInstanceID 的字段,虽然您可以通过 web 服务命令在技术上引用它,但使用起来并不明显
  2. 在 Acumatica 中,一旦使用此付款方式记录了一笔交易,付款方式的详细信息就会被锁定。这意味着要对其进行修改,您需要创建一种新的付款方式,并将旧的设置为不活动。
  3. 屏幕中有一个错误,只有在通过网络服务使用它时才会出现,这与上述项目有关。加载付款方式时,如果有任何交易,系统将禁用付款方式详细信息,但如果没有,则无法重新启用。从 Web 浏览器使用 Acumatica 时,这从来都不是问题,因为这些字段会在每次往返之间自动重新启用。但是,当通过 Web 服务自动执行此屏幕时,您实际上是在一次往返中执行所有操作。此问题已报告并将很快修复(内部 JIRA 参考是 AC-54456)

话虽这么说,但我们可以使用一些东西来使这个屏幕像其他屏幕一样易于通过 Web 服务使用,并解决它的局限性。通过创建自定义项目,我们可以在屏幕中添加PMInstanceID字段(以下简称Token ID字段)。您可以将此令牌存储在您的系统中,并将其用于未来的付款方式操作。在同一个定制项目中,我们还可以使支付方式详细信息始终处于启用状态,从而允许您更新现有卡的到期日期。这样做还解决了上面提到的系统不允许您向系统添加任何新付款方式的错误。自定义分为两部分:

  1. 正在覆盖 CustomerPaymentMethod DAC 以使 PMInstanceID 字段可从 UI 访问。这是通过将 PXUIField 属性附加到 PMInstanceID 字段来完成的:[PXUIField(DisplayName="Token ID", Visibility=PXUIVisibility.SelectorVisible)]。之后,可以使用布局编辑器将该字段添加到屏幕。
  2. 处理 CustomerPaymentMethod_RowSelected 事件以强制始终启用付款方式详细信息。我们还使用此事件处理程序在添加新支付方式时隐藏 Token ID 字段,否则此字段会显示 int.MinValue 直到支付方式被保存。事件的完整代码如下所示:

    protected void CustomerPaymentMethod_RowSelected(PXCache cache, PXRowSelectedEventArgs e, PXRowSelected InvokeBaseHandler)
    {
      if(InvokeBaseHandler != null)
        InvokeBaseHandler(cache, e);
    
      // Force the payment method details to always be enabled to facilitate working via web services
      PXUIFieldAttribute.SetEnabled(Base.Details.Cache, null, true);
    
      // When adding a new method, field will have a temporary value corresponding to int.MinValue - don't show it
      PXUIFieldAttribute.SetVisible<CustomerPaymentMethod.pMInstanceID>(cache, e.Row, cache.GetStatus(e.Row) != PXEntryStatus.Inserted);
    }
    

定制发布后,更新现有支付方式变得更加容易。下面的代码显示了如何添加付款方式,并检索您稍后将用于更新付款方式的令牌 ID:

    public int AddCreditCard(string customerID, string paymentMethod, string cardNumber, string expirationDate, string cvv, string nameOnCard)
    {
        if(_AR303010 == null) _AR303010 = _context.AR303010GetSchema();
        _context.AR303010Clear();

        var commands = new Command[]
        {
            new Value { Value = customerID, LinkedCommand = _AR303010.PaymentMethodSelection.Customer },
            new Value { Commit = true, LinkedCommand = _AR303010.Actions.Insert },
            new Value { Value = paymentMethod, LinkedCommand = _AR303010.PaymentMethodSelection.PaymentMethod },
            new Value { Value = "CCDNUM", LinkedCommand = _AR303010.PaymentMethodDetails.Description },
            new Value { Value = cardNumber, LinkedCommand = _AR303010.PaymentMethodDetails.Value, Commit = true },
            new Value { Value = "EXPDATE", LinkedCommand = _AR303010.PaymentMethodDetails.Description },
            new Value { Value = expirationDate,  LinkedCommand = _AR303010.PaymentMethodDetails.Value, Commit = true},
            new Value { Value = "CVV", LinkedCommand = _AR303010.PaymentMethodDetails.Description },
            new Value { Value = cvv, LinkedCommand = _AR303010.PaymentMethodDetails.Value, Commit = true },
            new Value { Value = "NAMEONCC", LinkedCommand = _AR303010.PaymentMethodDetails.Description },
            new Value { Value = nameOnCard,  LinkedCommand = _AR303010.PaymentMethodDetails.Value, Commit = true },
            _AR303010.Actions.Save,
            _AR303010.PaymentMethodSelection.TokenID
        };

        var result = _context.AR303010Submit(commands.ToArray());
        return int.Parse(result[0].PaymentMethodSelection.TokenID.Value);
    }

    public void UpdateCreditCardExpirationDate(string customerID, string paymentMethod, int tokenID, string expirationDate)
    {
        if (_AR303010 == null) _AR303010 = _context.AR303010GetSchema();
        _context.AR303010Clear();

        var commands = new Command[]
        {
            new Value { Value = customerID, LinkedCommand = _AR303010.PaymentMethodSelection.Customer },
            new Value { Commit = true, LinkedCommand = _AR303010.Actions.Insert },
            new Value { Value = paymentMethod, LinkedCommand = _AR303010.PaymentMethodSelection.PaymentMethod },
            new Value { Value = tokenID.ToString(), LinkedCommand = _AR303010.PaymentMethodSelection.TokenID },
            new Value { Value = "EXPDATE", LinkedCommand = _AR303010.PaymentMethodDetails.Description },
            new Value { Value = expirationDate,  LinkedCommand = _AR303010.PaymentMethodDetails.Value, Commit = true},
            _AR303010.Actions.Save,
        };

        var result = _context.AR303010Submit(commands.ToArray());
    }

    public void MakeCardInactive(string customerID, string paymentMethod, int tokenID)
    {
        if (_AR303010 == null) _AR303010 = _context.AR303010GetSchema();
        _context.AR303010Clear();

        var commands = new Command[]
        {
            new Value { Value = customerID, LinkedCommand = _AR303010.PaymentMethodSelection.Customer },
            new Value { Commit = true, LinkedCommand = _AR303010.Actions.Insert },
            new Value { Value = paymentMethod, LinkedCommand = _AR303010.PaymentMethodSelection.PaymentMethod },
            new Value { Value = tokenID.ToString(), LinkedCommand = _AR303010.PaymentMethodSelection.TokenID },
            new Value { Value = "False", LinkedCommand = _AR303010.PaymentMethodSelection.Active },
            _AR303010.Actions.Save,
        };

        var result = _context.AR303010Submit(commands.ToArray());
    }

我把这3个函数包装成一个class,实际使用起来很简单:

    var paymentMethodManager = new PaymentMethodManager(context);
    int tokenID = paymentMethodManager.AddCreditCard("ABARTENDE", "MASTERCARD", "5111111111111118", "122016", "123", "John Doe");
    paymentMethodManager.UpdateCreditCardExpirationDate("ABARTENDE", "MASTERCARD", tokenID, "032017");
    paymentMethodManager.MakeCardInactive("ABARTENDE", "MASTERCARD", tokenID);

截至目前,无法删除现有付款方式,您必须将其设为非活动状态。我已提出此增强功能的请求,将来可能会出现。

注意:我已将此答案中使用的所有代码放在 GitHub 的 https://github.com/gmichaud/acumatica-paymentmethod-ws-extensions