Adding Event Location to Customer Invoice.

Skyine Web Support asked on November 12, 2015 23:35

We are currently using events as products in order to have the event registration flow into the shopping cart process (Some events require payment). The client has asked us to add the Event Location to the invoice that gets emailed to the customer. Does anyone know the proper way to access the event data in the order invoice generation process? I've seen some posts that suggest using a custom ShoppingCartInfoProvider. Even using that process, I'm not quite sure how to get access to the event data. Seems like it should be easy. Thank you.

Correct Answer

Timothy Fenton answered on November 16, 2015 18:13

Hello again, i looked into it a bit further and there is a different exposed method you will need to override to get it in the email notification, it is:

 /// <summary>
    /// Sends order notification to customer.
    /// </summary>
    /// <param name="cartObj">Shopping cart info object</param>
    /// <param name="templateName">Name of the e-mail template which should be used for creating an e-mail</param>
    /// <param name="defaultTemplate">Name of the e-mail template which is used if primary template is not specified</param>
    /// <param name="defaultSubject">E-mail default subject. It is used if template subject is not specified</param>
    /// <param name="toCustomer">True - it is a notification to customer. False - it is a notification to administrator</param>
    /// <param name="eventSource">Source of the event which is logged when sending fails</param>
    protected virtual void SendEmailNotificationInternal(ShoppingCartInfo cartObj, string templateName, string defaultTemplate, string defaultSubject, bool toCustomer, string eventSource)
    {
        // Do not send if required data missing
        if ((cartObj == null) || (cartObj.Customer == null))
        {
            return;
        }

        // Ensure template name
        if (string.IsNullOrEmpty(templateName))
        {
            templateName = defaultTemplate;
        }

        // Get email template
        EmailTemplateInfo template = EmailTemplateProvider.GetEmailTemplate(templateName, cartObj.SiteName);

        // Check template presence
        if (template == null)
        {
            // Ensure event source
            if (string.IsNullOrEmpty(eventSource))
            {
                eventSource = "E-mail notification";
            }

            // Log error
            EventLogProvider.LogException(eventSource, "ECOMMERCE", new Exception(string.Format("Email template '{0}' for site '{1}' not found.", templateName, cartObj.SiteName)));

            return;
        }

        // Get order data
        OrderInfo oi = GetOrderInfo(cartObj.OrderId);

        if (oi != null)
        {
            string sendFrom = "";
            string sendTo = "";

            // Notification to customer
            if (toCustomer)
            {
                sendFrom = ECommerceSettings.SendEmailsFrom(cartObj.SiteName);
                sendTo = cartObj.Customer.CustomerEmail;
            }
            // Notification to administrator
            else
            {
                sendFrom = cartObj.Customer.CustomerEmail;
                sendTo = ECommerceSettings.SendEmailsTo(cartObj.SiteName);
            }

            // Get sender address for given template
            sendFrom = EmailHelper.GetSender(template, sendFrom);

            if (!string.IsNullOrEmpty(sendFrom) && !string.IsNullOrEmpty(sendTo))
            {
                string body = URLHelper.MakeLinksAbsolute(template.TemplateText);

                // Store original shopping cart culture
                string origCartCulture = cartObj.ShoppingCartCulture;

                // Use default culture 
                if (!toCustomer || !ECommerceSettings.UseCustomerCultureForEmails(cartObj.SiteName))
                {
                    cartObj.ShoppingCartCulture = CultureHelper.GetDefaultCultureCode(cartObj.SiteName);
                }

                // Prepare the macro resolver
                MacroResolver resolver = CreateEmailMacroResolver(cartObj);
                string[,] specialMacros = ShoppingCartInfoProvider.GetShoppingCartResolverSpecialMacros(cartObj);

                // Prepare the message
                EmailMessage message = new EmailMessage
                {
                    From = sendFrom,
                    Body = resolver.ResolveMacros(TextHelper.BulkReplace(body, specialMacros)),
                    Recipients = sendTo,
                    EmailFormat = EmailFormatEnum.Default
                };

                defaultSubject = ResHelper.GetString(defaultSubject, cartObj.ShoppingCartCulture);
                message.Subject = resolver.ResolveMacros(TextHelper.BulkReplace(EmailHelper.GetSubject(template, defaultSubject), specialMacros));
                message.PlainTextBody = resolver.ResolveMacros(TextHelper.BulkReplace(template.TemplatePlainText, specialMacros));
                message.CcRecipients = template.TemplateCc;
                message.BccRecipients = template.TemplateBcc;

                try
                {
                    // Send email
                    EmailHelper.ResolveMetaFileImages(message, template.TemplateID, EmailTemplateInfo.OBJECT_TYPE, ObjectAttachmentsCategories.TEMPLATE);
                    EmailSender.SendEmail(cartObj.SiteName, message);
                }
                catch (Exception ex)
                {
                    try
                    {
                        // Ensure event source
                        if (string.IsNullOrEmpty(eventSource))
                        {
                            eventSource = "E-mail notification";
                        }

                        EventLogProvider.LogException(eventSource, "ECOMMERCE", ex);
                    }
                    catch
                    {
                        // Unable to log the event
                    }
                }
                finally
                {
                    // Restore shopping cart culture
                    cartObj.ShoppingCartCulture = origCartCulture;
                }
            }
        }
    }

So, this time, you will basically check to see if the defaultTemplate is your customer payment notification template and then set the source data here just like before like this:

if(defaultTemplate == "Ecommerce.OrderStatusNotificationToCustomer")
{
    resolver.SetNamedSourceData("OrderEventLocation", GetEventLocationHere() );
}

Once you have done this, that macro should render in the email template..

0 votesVote for this answer Unmark Correct answer

Recent Answers


Timothy Fenton answered on November 13, 2015 13:17 (last edited on November 13, 2015 13:18)

Hello, you should be able to create a custom ShoppingCartInfoProvider, if you havent done this before there is an example in our documentaion here:

https://docs.kentico.com/display/K82/Custom+Info+provider+example

the method that you need to override is the following:

protected virtual string GetOrderInvoiceInternal(ShoppingCartInfo cart)
{
    // Do not process
    if ((cart == null) || string.IsNullOrEmpty(cart.SiteName))
    {
        return "";
    }

    // Get invoice template
    bool useGlobalInvoice = ECommerceSettings.UseGlobalInvoice(cart.SiteName);
    string template = ECommerceSettings.InvoiceTemplate(useGlobalInvoice ? "" : cart.SiteName);

    // Store original shopping cart culture
    string origCartCulture = cart.ShoppingCartCulture;

    // Use default culture for generating invoice
    cart.ShoppingCartCulture = CultureHelper.GetDefaultCultureCode(cart.SiteName);

    // Resolve macros
    MacroResolver mr = GetShoppingCartResolver(cart);

    template = TextHelper.BulkReplace(template, GetShoppingCartResolverSpecialMacros(cart));
    template = mr.ResolveMacros(template);

    // Restore shopping cart culture
    cart.ShoppingCartCulture = origCartCulture;

    // Add link to an order
    if (cart.OrderId > 0)
    {
        // Get link info
        string linkPage = URLHelper.AppendQuery(UIContextHelper.GetElementUrl("CMS.Ecommerce", "OrderProperties"), "objectid=" + cart.OrderId);
        string linkName = ResHelper.GetString("Ecommerce.OrderNotification.OpenOrder");

        // Set source parameters
        object[,] parameters = new object[1, 2];
        parameters[0, 0] = "OrderLink";
        parameters[0, 1] = string.Format("<a href=\"{0}\" target=\"_blank\" >{1}</a>", linkPage, linkName);

        mr.SetNamedSourceData(parameters);
    }

    return template;
}

So what you will need to do with this is simply add a new macro field to the macro resolver. This way in your template you can just add a macro like:

{% OrderEventLocation %}

For this you would just set the macro field sourcedata like this:

SetNamedSourceData("OrderEventLocation", GetEventLocationHere() );

inside of the GetEventLocationhere you will more than likely call an objectquery to the EventAttendeeInfoProvider.GetEventAttendeeInfo to get the NodeID of the proper event ( unless you already have this ) and then you will use that nodeid to get the event details using EventProvider.GetEvent() once you have the event you can get the location and return it to this method so that you are setting this sourcedata to the actual ordereventlocation.

Again, once you have done all this you will just add some line in your template that says:

Event Location: {% OrderEventLocation %}

and it will resolve the location

0 votesVote for this answer Mark as a Correct answer

Skyine Web Support answered on November 14, 2015 00:47

Thank you for your quick response Timothy.

Your method does allow me to modify the invoice that the back-end admin sees (I tried it) in the Orders Module. What I really want is to have the event location added to the invoice that gets sent to the customer "E-commerce - Order payment notification to customer".

0 votesVote for this answer Mark as a Correct answer

Timothy Fenton answered on November 16, 2015 12:05

does the {% OrderEventLocation %} not resolve in your email template for payment notification?

0 votesVote for this answer Mark as a Correct answer

Skyine Web Support answered on November 16, 2015 15:57

Hello Timothy,

That is correct. OrderEventLocation only shows on the back-end invoice not the email template. I re-ran again today to verify.

0 votesVote for this answer Mark as a Correct answer

Timothy Fenton answered on November 16, 2015 18:24

i forgot to mention this is part of the orderinfoprovider, not shoppingcartinfo provider so you will need to add a new custom provider for this or change the one you made before to orderinfoprovider

0 votesVote for this answer Mark as a Correct answer

Skyine Web Support answered on November 16, 2015 20:05 (last edited on November 16, 2015 20:46)

Timothy,

Is that the base implementation of "SendEmailNotificationInternal"? I'm assuming you are getting that from the source code repository? The only fear I have with using that chunk of logic is when we upgrade Kentico, the base code may have changed and now I need to request the source code again to fix possible broken code. If this is the only option, I'll go down that path. It would really be nice if we could just append the data to the original query and have it available to the email template macros.

0 votesVote for this answer Mark as a Correct answer

Timothy Fenton answered on November 16, 2015 20:41

Hello again, this is coming from source code, however you could really get a watered down version of this code ( no comments, variable name different etc ) by browsing the assembly, or decompiling the DLL. For example I use ILSpy to inspect the Cms.Ecommerce.dll and go to OrderInfoProvider and then to SendEmailNotificationInternal and i can get the same general code that i provided to you here. This code wont have comments and the variable names will be different but it should execute the same as if you ran the code I have given you.

0 votesVote for this answer Mark as a Correct answer

   Please, sign in to be able to submit a new answer.