Page 1 of 1

Store custom field in email

Posted: Thu Jun 27, 2013 9:37 am
by jguengerich
I would like to add a store custom field to an email template. I tried doing this in the template (note this is a simple test criteria, my "real" code would specify the TableName and ForeignKeyId as well):

Code: Select all

#if (${store.CustomFields.Find(cField => cField.FieldName == fieldName).FieldValue} == "true")
Yes
#else
No
#end
but I get this error:
Error generating email messages for template 'Customer Order Notification' having subject 'Confirmation - Order Number $order.OrderNumber'.
Exception: Encountered "= >" at line 96, column 39. Was expecting one of: "," ... ")" ... ... ... "[" ... "true" ... "false" ... ... "{" ... "," ... Stack Trace: at NVelocity.App.VelocityEngine.Evaluate(IContext context, TextWriter writer, String logTag, TextReader reader) at CommerceBuilder.Messaging.NVelocityEngine.Process(Hashtable parameters, String template) at CommerceBuilder.Messaging.EmailTemplate.GenerateMailMessages() at CommerceBuilder.Messaging.EmailTemplate.Send(Boolean async) Inner Exception: Encountered "= >" at line 96, column 39. Was expecting one of: "," ... ")" ... ... ... "[" ... "true" ... "false" ... ... "{" ... "," ... Inner Exception Stack Trace: at NVelocity.Runtime.Parser.Parser.Parse(TextReader reader, String templateName) at NVelocity.Runtime.RuntimeInstance.Parse(TextReader reader, String templateName, Boolean dumpNamespace) at NVelocity.Runtime.RuntimeInstance.Parse(TextReader reader, String templateName) at NVelocity.App.VelocityEngine.Evaluate(IContext context, TextWriter writer, String logTag, TextReader reader)

I don't want to use a #foreach ($oneField in $store.CustomFields) loop with an #if statement inside, because as the number of store custom fields grows it will take longer and longer to evaluate. (Actually, the Find() method I'm trying would probably take longer and longer too, but I wasn't sure what else to try).

It doesn't seem like I can use the CustomFieldRepository class in the email template either.

How can I add a store custom field to an email template without it taking order(N) to evaluate? I have the source code, if that helps. Any pointers about where to look in the source code and how to include a parameter to allow access to the CustomFieldRepository when processing email templates?

Re: Store custom field in email

Posted: Mon Jul 01, 2013 11:10 am
by ForumsAdmin
NVelocity supports a very limited syntax. You can't do full programming in NVelocity.
Check the following for NVelocity Syntax reference
http://help.ablecommerce.com/mergedProj ... erence.htm
http://velocity.apache.org/engine/relea ... troduction
http://velocity.apache.org/engine/devel ... guide.html

Re: Store custom field in email

Posted: Mon Jul 01, 2013 1:37 pm
by jguengerich
I realize you can't do full programming, hence the question :-).

The AbleCommerce User's Guide appendix you linked to says:
When you reference variables you are accessing the object through the .NET framework. You can use traditional .NET syntax to access properties and methods. A common example might be to provide string formats:
$User.LastLoginDate.ToString("mm-ddd-yyyy")
That is why I tried store.CustomFields.Find(...); I figured store = object, CustomFields = property, Find(...) = method, so maybe it would work.

In any case, I'd still be interested if anyone knows a (relatively) simple way to accomplish my original question:
How can I add a store custom field to an email template without it taking order(N) to evaluate?

Re: Store custom field in email

Posted: Mon Jul 08, 2013 7:37 am
by jguengerich
I eventually came up with 2 different solutions. Note that the info I want to keep track of is specific to each order.

Solution 1:
In CommerceBuilder\Messaging\EmailProcessor.cs (source code), added:

Code: Select all

using NHibernate.Criterion
and changed the following method:

Code: Select all

        public static void ProcessEmails(int orderStatusId, Hashtable parameters)
        {
            parameters["store"] = AbleContext.Current.Store;

            // MODS START HERE Get custom fields and add to parameters list
            if (parameters.ContainsKey("order"))
            {
                CustomFieldRepository customFieldsRep = new CustomFieldRepository();
                NHibernate.ICriteria criteria = NHibernateHelper.CreateCriteria<CommerceBuilder.Stores.CustomField>()
                    .Add(
                            Restrictions.Eq("Store.Id", AbleContext.Current.StoreId) &&
                            Restrictions.Eq("TableName", "ac_Orders") &&
                            Restrictions.Eq("ForeignKeyId", ((CommerceBuilder.Orders.Order)parameters["order"]).Id) &&
                            Restrictions.Eq("FieldName", "MyFieldname"));
                IList<CommerceBuilder.Stores.CustomField> customFields = customFieldsRep.LoadForCriteria(criteria);
                parameters["customfields"] = customFields;
            }
            // MODS END HERE

            // NEED TO GET THE EMAIL TEMPLATES FOR THE ORDER STATUS
            // AbleContext.Resolve <IEmailTemplateRepository>().LoadForOrderStatus(orderStatusId);
            IList<EmailTemplate> emailTemplates = EntityLoader.Load<OrderStatus>(orderStatusId).EmailTemplates;
            foreach (EmailTemplate template in emailTemplates)
            {
                if (template != null)
                {
                    foreach (string key in parameters.Keys)
                    {
                        template.Parameters[key] = parameters[key];
                    }
                    template.Send();
                }
            }
        }
Also added the same code to the ProcessEmails(StoreEvent storeEvent, Hashtable parameters) method in the same file. Note that where I have "MyFieldname" above, I actually use a string specific to my implementation.

In the "Customer Order Notification.html" email template, I added the following code where I wanted to display the info stored in the custom field:

Code: Select all

#if ($customfields.Count > 0)
#foreach ($customfield in $customfields)
#if ($customfield.FieldValue == "true")
Yes
#else
No
#end
#end
#else
No
#end
I just wanted a simple true/false value, you could obviously expand on this for more complicated behavior and for other email templates.

Solution 2 (the one I'll probably actually use):
Used an OrderNote. In the Email template, added the following code where I wanted to display the info stored in the note:

Code: Select all

#set ($myValue = "No")
#if ($order.Notes.Count > 0)
#foreach ($orderNote in $order.Notes)
#if ($orderNote.Comment == "My Comment")
#set ($myValue = "Yes")
#end
#end
#end
$myValue
Note that where I have "My Comment" above, I actually use a string specific to my implementation.