web
You’re offline. This is a read only version of the page.
close
Skip to main content

Announcements

No record found.

News and Announcements icon
Community site session details

Community site session details

Session Id :
Supply chain | Supply Chain Management, Commerce
Suggested Answer

Getting error while using custom tender type Id on tender line

(1) ShareShare
ReportReport
Posted on by 64

Hello Retail experts,

I have created a custom payment method (5001) in the back office and added a custom Default function by extending the enum. I have created a new payment method (5001) on the store using my custom payment method and I have configured my custom POS operation (5001) there.

pastedimage1669389527127v2.png

pastedimage1669389622330v3.png

I have also implemented a POS operation that adds a tender line to the cart with Tender type Id = 5001

I am getting the below exception while adding a tender line to the cart with my custom tender type Id (5001). When I use any other tender type Id (Cash or Other), I don't get any error and am able to complete the transaction.

pastedimage1669389161762v1.png
I also tried to debug the request handler for SaveTenderLineRequest to get more information on the exception. I am getting below exception on CRT.

pastedimage1669390614294v5.png

Below is the stack trace of CRT exception:

"   at Microsoft.Dynamics.Commerce.Runtime.Services.PaymentManagerService.<ResolvePaymentService>d__12.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 Microsoft.Dynamics.Commerce.Runtime.Services.PaymentManagerService.<AuthorizePayment>d__7.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 Microsoft.Dynamics.Commerce.Runtime.CommerceRuntime.<Execute>d__48`1.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 Microsoft.Dynamics.Commerce.Runtime.CommerceRuntime.<Execute>d__48`1.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 Microsoft.Dynamics.Commerce.Runtime.Workflow.CartWorkflowHelper.<AddOrUpdateTenderLine>d__39.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 Microsoft.Dynamics.Commerce.Runtime.Workflow.SaveTenderLineRequestHandler.<CalculateRequiredReasonCodesAndAddOrUpdateTenderLine>d__8.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 Microsoft.Dynamics.Commerce.Runtime.Workflow.SaveTenderLineRequestHandler.<CreateTenderLine>d__7.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 Microsoft.Dynamics.Commerce.Runtime.Workflow.SaveTenderLineRequestHandler.<Process>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 Microsoft.Dynamics.Commerce.Runtime.CommerceRuntime.<Execute>d__48`1.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 Microsoft.Dynamics.Commerce.Runtime.CommerceRuntime.<Execute>d__48`1.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.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()\r\n   at Contoso.ModernPosPackagingSample.CommerceRuntime.RequestHandlers.MyTest.<Execute>d__2.MoveNext()"


Any idea what else I am missing?

I have the same question (0)
  • Suggested answer
    Salmani.M Profile Picture
    2 on at

    Hi,

    The error "Unable to retrieve tender service for operation" typically means that the Commerce Runtime (CRT) is unable to find a suitable handler for the payment operation you're trying to perform (e.g., AuthorizePayment, VoidPayment, etc.). To resolve this, you need to implement a custom handler that supports your custom payment operation ID. Below is an example of how to implement a handler for a custom payment method using operation ID 5001.

     

    namespace YourNamespace.CommerceRuntime.PaymentHandlers
    {
        using System;
        using System.Threading.Tasks;
        using System.Collections.Generic;
        using Microsoft.Dynamics.Commerce.Runtime;
        using Microsoft.Dynamics.Commerce.Runtime.Services.Messages;
        using Microsoft.Dynamics.Commerce.Runtime.Messages;
       
    public class WalletPaymentService : IOperationRequestHandlerAsync, IOperationAware, IRequestHandlerAsync, ISupportedTypesAware
    {
        public IEnumerable<int> SupportedOperationIds => new int[1] { 5001 };
        public IEnumerable<Type> SupportedRequestTypes => new Type[5]
        {
            typeof(CalculatePaymentAmountServiceRequest),
            typeof(AuthorizePaymentServiceRequest),
            typeof(VoidPaymentServiceRequest),
            typeof(GetChangePaymentServiceRequest),
            typeof(IsTenderLineLinkedRefundableServiceRequest)
        };
        public Task<Response> Execute(Request request)
        {
            ThrowIf.Null(request, "request");
            if (!(request is CalculatePaymentAmountServiceRequest request2))
            {
                if (!(request is AuthorizePaymentServiceRequest request3))
                {
                    if (!(request is VoidPaymentServiceRequest request4))
                    {
                        if (!(request is GetChangePaymentServiceRequest request5))
                        {
                            if (request is IsTenderLineLinkedRefundableServiceRequest request6)
                            {
                                return IsLinkedRefundable(request6);
                            }
                            throw new NotSupportedException(string.Format(CultureInfo.InvariantCulture, "Request '{0}' is not supported.", request.GetType()));
                        }
                        return GetChange(request5);
                    }
                    return CancelPayment(request4);
                }
                return AuthorizePayment(request3);
            }
            return CalculatePaymentAmount(request2);
        }
        private static Task<Response> CalculatePaymentAmount(CalculatePaymentAmountServiceRequest request)
        {
            ThrowIf.Null(request, "request");
            CalculatePaymentAmountServiceResponse result = new CalculatePaymentAmountServiceResponse(request.TenderLine);
            return Task.FromResult((Response)result);
        }
        private static Task<Response> AuthorizePayment(AuthorizePaymentServiceRequest request)
        {
            ThrowIf.Null(request, "request");
            request.TenderLine.Status = TenderLineStatus.Committed;
            request.TenderLine.IsVoidable = true;
            AuthorizePaymentServiceResponse result = new AuthorizePaymentServiceResponse(request.TenderLine);
            return Task.FromResult((Response)result);
        }
        private static Task<Response> CancelPayment(VoidPaymentServiceRequest request)
        {
            ThrowIf.Null(request, "request");
            if (request.TenderLine == null)
            {
                throw new PaymentException(PaymentErrors.Microsoft_Dynamics_Commerce_Runtime_InvalidPaymentRequest, "Request's Tender Line is null.");
            }
            request.TenderLine.Status = TenderLineStatus.Voided;
            request.TenderLine.IsVoidable = false;
            VoidPaymentServiceResponse result = new VoidPaymentServiceResponse(request.TenderLine);
            return Task.FromResult((Response)result);
        }
        private static Task<Response> GetChange(GetChangePaymentServiceRequest request)
        {
            ThrowIf.Null(request, "request");
            if (string.IsNullOrWhiteSpace(request.ChangeTenderTypeId))
            {
                throw new ArgumentException("request.TenderType is null", "request");
            }
            TenderLine tenderLine = new TenderLine
            {
                Amount = decimal.Negate(request.ChangeAmount),
                Currency = request.CurrencyCode,
                TenderLineId = Guid.NewGuid().ToString("N"),
                TenderTypeId = request.ChangeTenderTypeId,
                Status = TenderLineStatus.Committed,
                IsVoidable = true,
                IsChangeLine = true,
                ChannelId = request.Transaction.ChannelId
            };
            GetChangePaymentServiceResponse result = new GetChangePaymentServiceResponse(tenderLine);
            return Task.FromResult((Response)result);
        }
        private static Task<Response> IsLinkedRefundable(IsTenderLineLinkedRefundableServiceRequest request)
        {
            IsTenderLineLinkedRefundableServiceResponse result = new IsTenderLineLinkedRefundableServiceResponse(isLinkedRefundable: false);
            return Task.FromResult((Response)result);
        }
    }
    }
    
     

    Make sure the Operation ID assigned to your payment method in HQ matches the one you define in SupportedOperationIds. Also, ensure Process locally is checked if you want the CRT to handle the operation without calling an external connector. Once this handler is in place and built into your CRT extension package, your custom payment method should work as expected.

  • S Gopi Krishna Profile Picture
    673 Super User 2026 Season 1 on at
    I'm not sure about the approach you are taking, and I believe this approach is not a proper one, you have to extend the existing card payment method to support new card gateways / processors, by building a custom payment connector for it. Please refer the MS document for more details. Also we will wait and see what others have to say on this. https://learn.microsoft.com/en-us/dynamics365/commerce/dev-itpro/deploy-payment-connector

Under review

Thank you for your reply! To ensure a great experience for everyone, your content is awaiting approval by our Community Managers. Please check back later.

Helpful resources

Quick Links

Introducing the 2026 Season 1 community Super Users

Congratulations to our 2026 Super Stars!

Meet the Microsoft Dynamics 365 Contact Center Champions

We are thrilled to have these Champions in our Community!

Congratulations to the April Top 10 Community Leaders

These are the community rock stars!

Leaderboard > Supply chain | Supply Chain Management, Commerce

#1
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 164 Super User 2026 Season 1

#2
Laurens vd Tang Profile Picture

Laurens vd Tang 105 Super User 2026 Season 1

#3
Zain Mehmood Profile Picture

Zain Mehmood 89 Most Valuable Professional

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans