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

Notifications

Announcements

No record found.

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
    633 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

Responsible AI policies

As AI tools become more common, we’re introducing a Responsible AI Use…

Neeraj Kumar – Community Spotlight

We are honored to recognize Neeraj Kumar as our Community Spotlight honoree for…

Leaderboard > Supply chain | Supply Chain Management, Commerce

#1
Laurens vd Tang Profile Picture

Laurens vd Tang 299 Super User 2025 Season 2

#2
Siv Sagar Profile Picture

Siv Sagar 183 Super User 2025 Season 2

#3
André Arnaud de Calavon Profile Picture

André Arnaud de Cal... 117 Super User 2025 Season 2

Last 30 days Overall leaderboard

Product updates

Dynamics 365 release plans