Background : Order completed email will get sent to the customer between clicking finish order and then being sent to cybersource to pay for the order, which doesn't look correct to the user (order finished, email sent as completed, but still on cybersource site entering CC info to pay - so not really finished). Taking the existing SendOrderPlacedCustomerNotification, copying functionality, but triggering after the cybersource payment authorized response message by declaring a new function SendPaymentAuthorizedCustomerNotificationEmail.
(Eventual) Error : The requested service 'Nop.Plugin.Payments.IngramCyberSource.IngramServices.IngramWorkflowMessageService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.
CODE :
*********** DependencyRegistrar *****************
using Autofac;
using Nop.Core.Configuration;
using Nop.Core.Infrastructure;
using Nop.Core.Infrastructure.DependencyManagement;
using Nop.Core.Plugins;
using Nop.Services.Messages;
using System;
using System.Linq;
using Nop.Plugin.Payments.IngramCyberSource.IngramServices;
namespace Nop.Plugin.Payments.IngramCyberSource.Infrastructure
{
public class DependencyRegistrar : IDependencyRegistrar
{
private const string CONTEXT_NAME = "nop_object_context_ingram_cybersource_workflowmessage";
public int Order
{
get
{
return 1;
}
}
public void Register(ContainerBuilder builder, ITypeFinder typeFinder, NopConfig config)
{
//Is this plugin installed??
var isInstalled = false;
var types = typeFinder.FindClassesOfType<IPluginFinder>(true);
if (types.Count() == 1)
{
var plugins = Activator.CreateInstance(types.First()) as IPluginFinder;
var plug = plugins.GetPluginDescriptorBySystemName("Payments.IngramCyberSource");
if (plug != null && plug.Installed)
{
isInstalled = true;
}
}
if (isInstalled)
{
// register service
builder.RegisterType<IngramWorkflowMessageService>()
.As<WorkflowMessageService>()
.InstancePerLifetimeScope();
}
}
}
}
*********** IngramWorkflowMessageService **********************
using Nop.Services.Messages;
using System;
using System.Collections.Generic;
using Nop.Core;
using Nop.Core.Domain.Messages;
using Nop.Services.Events;
using Nop.Services.Localization;
using Nop.Services.Stores;
using Nop.Core.Domain.Orders;
namespace Nop.Plugin.Payments.IngramCyberSource.IngramServices
{
public class IngramWorkflowMessageService : WorkflowMessageService
{
#region Variables
private readonly IMessageTokenProvider _messageTokenProvider;
private readonly IStoreService _storeService;
private readonly IStoreContext _storeContext;
private readonly IEventPublisher _eventPublisher;
#endregion
#region Constructor
public IngramWorkflowMessageService(IMessageTemplateService messageTemplateService, IQueuedEmailService queuedEmailService, ILanguageService languageService, ITokenizer tokenizer, IEmailAccountService emailAccountService, IMessageTokenProvider messageTokenProvider, IStoreService storeService, IStoreContext storeContext, EmailAccountSettings emailAccountSettings, IEventPublisher eventPublisher) : base(messageTemplateService, queuedEmailService, languageService, tokenizer, emailAccountService, messageTokenProvider, storeService, storeContext, emailAccountSettings, eventPublisher)
{
_messageTokenProvider = messageTokenProvider;
_storeContext = storeContext;
_storeService = storeService;
_eventPublisher = eventPublisher;
}
#endregion
#region Service Overrides/Addons
internal int SendPaymentAuthorizedCustomerNotification(Order order, int languageId, string attachmentFilePath = null, string attachmentFileName = null)
{
if (order == null)
throw new ArgumentNullException("order");
var store = _storeService.GetStoreById(order.StoreId) ?? _storeContext.CurrentStore;
languageId = EnsureLanguageIsActive(languageId, store.Id);
var messageTemplate = GetActiveMessageTemplate("PaymentAuthorized.CustomerNotification", store.Id);
if (messageTemplate == null)
return 0;
//email account
var emailAccount = GetEmailAccountOfMessageTemplate(messageTemplate, languageId);
//tokens
var tokens = new List<Token>();
_messageTokenProvider.AddStoreTokens(tokens, store, emailAccount);
_messageTokenProvider.AddOrderTokens(tokens, order, languageId);
_messageTokenProvider.AddCustomerTokens(tokens, order.Customer);
//event notification
_eventPublisher.MessageTokensAdded(messageTemplate, tokens);
var toEmail = order.BillingAddress.Email;
var toName = string.Format("{0} {1}", order.BillingAddress.FirstName, order.BillingAddress.LastName);
return SendNotification(messageTemplate, emailAccount,
languageId, tokens,
toEmail, toName,
attachmentFilePath,
attachmentFileName);
}
#endregion
#region Methods
#endregion
}
}
******************* PaymentCyberSourceController ***********************************
using System.Collections.Generic;
using System.Web.Mvc;
using Nop.Core;
using Nop.Core.Domain.Payments;
using Nop.Core.Domain.Orders;
using Nop.Plugin.Payments.IngramCyberSource.Models;
using Nop.Services.Configuration;
using Nop.Services.Orders;
using Nop.Services.Payments;
using Nop.Services.Logging;
using Nop.Web.Framework.Controllers;
using System.Text;
using System;
using System.Linq;
using Nop.Services.Events;
using Perseus.DataTypes;
using Perseus.Messages;
using Perseus.nopObjects.Messages;
using Perseus.nopObjects.Services;
using Nop.Services.Security;
using Nop.Services.Common;
using Nop.Core.Infrastructure;
using Nop.Plugin.Payments.IngramCyberSource.IngramServices;
using Nop.Services.Messages;
using Autofac;
using System.Web.Compilation;
namespace Nop.Plugin.Payments.IngramCyberSource.Controllers
{
public class PaymentCyberSourceController : BasePaymentController {
private readonly ISettingService _settingService;
private readonly IPaymentService _paymentService;
private readonly IOrderService _orderService;
private readonly IOrderProcessingService _orderProcessingService;
private readonly CyberSourcePaymentSettings _cyberSourcePaymentSettings;
private readonly PaymentSettings _paymentSettings;
private readonly ILogger _loggerService;
private readonly IEncryptionService _encryptionService;
private readonly IEventPublisher _eventPublishingService;
private readonly OrderSettings _orderSettings;
private readonly IPdfService _pdfService;
private readonly IngramWorkflowMessageService _ingramWorkflowMessageService;
//TODO test code
private readonly IComponentContext _con;
#if UseAkka
private readonly static object ActorSystemKey = new object();
private static ActorSystem ActorSystem { get; set; }
#endif
public PaymentCyberSourceController(ISettingService settingService,
IPaymentService paymentService, IOrderService orderService,
IOrderProcessingService orderProcessingService,
CyberSourcePaymentSettings cyberSourcePaymentSettings,
PaymentSettings paymentSettings,
ILogger loggerService,
IEncryptionService encryptionService,
IEventPublisher eventPublishingService) {
this._settingService = settingService;
this._paymentService = paymentService;
this._orderService = orderService;
this._orderProcessingService = orderProcessingService;
this._cyberSourcePaymentSettings = cyberSourcePaymentSettings;
this._paymentSettings = paymentSettings;
this._loggerService = loggerService;
this._encryptionService = encryptionService;
this._eventPublishingService = eventPublishingService;
//TODO test code
this._con = EngineContext.Current.Resolve<IComponentContext>();
var myTYpes1 = _con.ComponentRegistry.Registrations.Where(r => typeof(WorkflowMessageService).IsAssignableFrom(r.Activator.LimitType)).Select(r => r.Activator.LimitType);
var myTYpes2 = _con.ComponentRegistry.Registrations.Where(r => typeof(IWorkflowMessageService).IsAssignableFrom(r.Activator.LimitType)).Select(r => r.Activator.LimitType);
// Jed-49 : PaymentAuthorizedEmail
this._orderSettings = EngineContext.Current.Resolve<OrderSettings>();
this._pdfService = EngineContext.Current.Resolve<IPdfService>();
this._ingramWorkflowMessageService = EngineContext.Current.Resolve<IngramWorkflowMessageService>();
#if UseAkka
if (ActorSystem == null) {
lock (ActorSystemKey) {
if (ActorSystem == null) {
try {
_loggerService.Information("Creating Cybersource Payment Plugin Actor System...");
var config = ConfigurationFactory.ParseString(AkkaConfiguration);
ActorSystem = ActorSystem.Create("OrderTransmitter", config);
_loggerService.Information("Cybersource Payment Plugin Actor System Created.");
} catch (Exception ex) {
_loggerService.Error("Exception raised while creating Cybersource Payment Plugin Actor System:", ex);
throw;
}
}
}
}
#endif
}
Although the myTypes variables show the services as expected:
myTYpes1 - myTYpes2 : Results View = Expanding the Results View will enumerate the IEnumerable:
[0] = {Name = "WorkflowMessageService" FullName = "Nop.Services.Messages.WorkflowMessageService"}
[1] = {Name = "IngramWorkflowMessageService" FullName = "Nop.Plugin.Payments.IngramCyberSource.IngramServices.IngramWorkflowMessageService"}
- when it gets to resolving I get:
An error occurred when trying to create a controller of type 'Nop.Plugin.Payments.IngramCyberSource.Controllers.PaymentCyberSourceController'. Make sure that the controller has a parameterless public constructor.
- and digging into the inner exceptions finally shows
The requested service 'Nop.Plugin.Payments.IngramCyberSource.IngramServices.IngramWorkflowMessageService' has not been registered. To avoid this exception, either register a component to provide the service, check for service registration using IsRegistered(), or use the ResolveOptional() method to resolve an optional dependency.