Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
AI OnAI Off
Five New Optimizely Certifications are Here! Validate your expertise and advance your career with our latest certification exams. Click here to find out more
Regarding your first attempt,
Activation error occurred while trying to get instance of type, key "TermsPayment"
is not caused by
It is unable to convert it to IPayment and gives a null exception.
The problem is your default constructor (as seen by structuremap) is public TermsPayment(MetaClass metaClass), and it does not know how to create an instance of MetaClass.
I am trying to implement a custom payment type for Serialized carts, it is failing when we convert the cart to a purchase order. Below are the different ways I tried out but I am still having the same issue.
Attempt 1: Inheriting from Payment (I opened the reflector and I see payment types like CashCardPayment, CreditCardPayment etc are doing the same)
using System; using System.Collections; using System.Collections.Generic; using System.Linq; using System.Runtime.Serialization; using System.Text; using System.Threading.Tasks; using EPiServer.Commerce.Order; using Mediachase.Commerce.Orders; using Mediachase.MetaDataPlus.Configurator; namespace Whereoware.Commerce.Payments { [Serializable] public class TermsPayment : Payment { private static MetaClass _MetaClass; /// <summary> /// Gets the credit card payment meta class. /// </summary> /// <value>The credit card payment meta class.</value> public static MetaClass TermsPaymentMetaClass => _MetaClass ?? (_MetaClass = MetaClass.Load(OrderContext.MetaDataContext, "TermsPayment")); public TermsPayment() : base(TermsPayment.TermsPaymentMetaClass) { this.PaymentType = PaymentType.Other; this.ImplementationClass = GetType().AssemblyQualifiedName; } public TermsPayment(MetaClass metaClass) : base(metaClass) { this.PaymentType = PaymentType.Other; this.ImplementationClass = GetType().AssemblyQualifiedName; } protected TermsPayment(SerializationInfo info, StreamingContext context) : base(info, context) { this.PaymentType = PaymentType.Other; this.ImplementationClass = GetType().AssemblyQualifiedName; } public string TermsOption { get { return this.GetString("TermsOption"); } set { this["TermsOption"] = (object)value; } } public string PurchaseOrderNumber { get { return this.GetString("PurchaseOrderNumber"); } set { this["PurchaseOrderNumber"] = (object)value; } } } }
I also have a TermsPaymentMethod class that implements PaymentMethodBase which is an abstract class.
using System; using EPiServer.Commerce.Order; using EPiServer.ServiceLocation; using Mediachase.Commerce.Orders.Managers; namespace CustomPayment.Commerce.PaymentMethods { [ServiceConfiguration(typeof(IPaymentMethod))] public class TermsPaymentMethod : PaymentMethodBase { public override string SystemKeyword => "Manual"; protected readonly Guid _paymentMethodId; public TermsPaymentMethod(Guid paymentMethodId) : this(ServiceLocator.Current.GetInstance<IOrderGroupFactory>(), paymentMethodId) { _paymentMethodId = paymentMethodId; } public TermsPaymentMethod(IOrderGroupFactory orderGroupFactory, Guid paymentMethodId) : base(orderGroupFactory, paymentMethodId) { } public override IPayment CreatePayment(decimal amount, IOrderGroup orderGroup) { string implementationClassName = PaymentManager.GetPaymentMethod(base.PaymentMethodId, false).PaymentMethod[0].PaymentImplementationClassName; var type = Type.GetType(implementationClassName); var payment = type == null ? orderGroup.CreatePayment(OrderGroupFactory) : orderGroup.CreatePayment(OrderGroupFactory, type); payment.PaymentMethodId = PaymentMethodId; payment.PaymentMethodName = Name; payment.Amount = amount; payment.PaymentType = Mediachase.Commerce.Orders.PaymentType.Other; return payment; } public override bool ValidateData() { return true; } } }
I then create a Payment type inside my checkout controller and use the CreatePayment(decimal amount, IOrderGroup orderGroup) of IPaymentMethod which in my case triggers TermsPaymentMethod implementation.
I can see that my implementation class is now TermsPayment as well in the payment object. But it fails when I convert the cart to a purchase order.
Below is the stack trace:
Activation error occurred while trying to get instance of type, key "TermsPayment"
Upon checking the reflector I see that Epi tries to create a payment type :
public IPayment CreatePayment(Type paymentType) { return ServiceLocator.Current.GetInstance(paymentType) as IPayment; }
It is unable to convert it to IPayment and gives a null exception.
Attempt 2:
Everything is the same as the previous attempt other than the payment type implementation
using System.Collections; using EPiServer.Commerce.Order; using EPiServer.Commerce.Order.Internal; using EPiServer.Commerce.Storage; using Mediachase.Commerce.Orders; using Newtonsoft.Json; namespace Whereoware.Commerce.Payments { [JsonConverter(typeof(PaymentConverter))] public class TermsPayment : SerializablePayment, IPayment, IExtendedProperties { public TermsPayment() { this.Properties = new Hashtable(); this.BillingAddress = (IOrderAddress)new SerializableOrderAddress(); this.PaymentType = PaymentType.Other; this.ImplementationClass = GetType().AssemblyQualifiedName; } } }
I refferd to the article below for the second attempt:
https://world.episerver.com/forum/developer-forum/Episerver-Commerce/Thread-Container/2017/10/how-to-make-serializable-carts-to-work-with-icreditcardpayment-authorize-net/
But still have the same issue when it converts it to a purchase order:
"Value cannot be null"
at Mediachase.Commerce.Storage.MetaStorageObservableCollection`2.OnListChanged(Object sender, NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection`1.OnCollectionChanged(NotifyCollectionChangedEventArgs e) at System.Collections.ObjectModel.ObservableCollection`1.InsertItem(Int32 index, T item) at EPiServer.Commerce.Order.IOrderGroupExtensions.CopyPayments(IOrderForm sourceForm, IOrderForm destinationForm, IOrderGroup destinationOrderGroup, IOrderGroupFactory orderGroupFactory) at EPiServer.Commerce.Order.IOrderGroupExtensions.CopyOrderForm(IOrderGroup orderGroup, IOrderGroup sourceOrderGroup, IOrderGroupFactory orderGroupFactory) at EPiServer.Commerce.Order.IOrderGroupExtensions.CopyFrom(IOrderGroup orderGroup, IOrderGroup sourceOrderGroup, IOrderGroupFactory orderGroupFactory) at EPiServer.Commerce.Order.Internal.SerializableCartProvider.SaveAsPurchaseOrder(ICart cart) at EPiServer.Commerce.Order.Internal.DefaultOrderRepository.SaveAsPurchaseOrder(IOrderGroup cart)
I am also attaching a screen shot of the PaymentMethod table:
https://www.screencast.com/t/tRdQ5xs4
I have been struggling on this since 2 days now, any help or leads on this is highly appreciated.