Store custom field in email

For general questions and discussions specific to the AbleCommerce GOLD ASP.Net shopping cart software.
Post Reply
jguengerich
Commodore (COMO)
Commodore (COMO)
Posts: 436
Joined: Tue May 07, 2013 1:59 pm

Store custom field in email

Post by jguengerich » Thu Jun 27, 2013 9:37 am

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?
Jay

User avatar
ForumsAdmin
AbleCommerce Moderator
AbleCommerce Moderator
Posts: 399
Joined: Wed Mar 13, 2013 7:19 am

Re: Store custom field in email

Post by ForumsAdmin » Mon Jul 01, 2013 11:10 am

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

jguengerich
Commodore (COMO)
Commodore (COMO)
Posts: 436
Joined: Tue May 07, 2013 1:59 pm

Re: Store custom field in email

Post by jguengerich » Mon Jul 01, 2013 1:37 pm

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?
Jay

jguengerich
Commodore (COMO)
Commodore (COMO)
Posts: 436
Joined: Tue May 07, 2013 1:59 pm

Re: Store custom field in email

Post by jguengerich » Mon Jul 08, 2013 7:37 am

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.
Jay

Post Reply