In one of our
requirement, we have to save WFFM form fields data in word document’s mail
merge fields. This word document should be generated from mail merge template document.
I created WFFM form
and created a new Save action under “/sitecore/system/Modules/Web
Forms for Marketers/Settings/Actions/Save Actions”
My WFFM form looks as
Sample WFFM Form |
I bind the newly
created Save action to this WFFM form.
I am using DocumentFormat.OpenXml
to generate word document for mail merge fields.
Here is my word
document template for mail merge fields
Word Mail Merge |
Below is code for
this WFFM Save Action.
using System;
using System.Collections.Generic;
using System.Linq;
using Sitecore.Data;
using Sitecore.WFFM.Abstractions.Actions;
using System.IO;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml;
namespace SitecorePOCinMVC.Web
{
public class MyCustomAction : ISaveAction
{
public ID ActionID { get; set; }
public string UniqueKey { get; set; }
public ActionType ActionType { get; private set; }
public ActionState QueryState(ActionQueryContext queryContext)
{
return ActionState.Enabled;
}
public ActionCallContext Context { get; set; }
public void Execute(ID formId, AdaptedResultList adaptedFields, ActionCallContext actionCallContext = null, params object[] data)
{
string companyName = adaptedFields.GetValueByFieldID("{083F0126-4912-4ED7-A4B4-D55869C73D67}");
string companyID = adaptedFields.GetValueByFieldID("{5B128D2F-E671-4A07-BE7F-4BDE9385D4A9}");
string entryDesc = adaptedFields.GetValueByFieldID("{C87FD86C-71A4-432F-8B78-9990F16F0477}");
Dictionary<string, string> wffmFields = new Dictionary<string, string>();
wffmFields.Add("Company Name",
companyName);
wffmFields.Add("Company ID",
companyID);
wffmFields.Add("Entry Desc",
entryDesc);
try
{
OpenXMLUtility.WFFMFieldsToMailMerge(wffmFields);
}
catch (Exception ex)
{
System.IO.File.AppendAllText("d:\\sitecoretext.txt", "PDF Error : -" + ex.Message);
}
}
}
class OpenXMLUtility
{
public static void WFFMFieldsToMailMerge(Dictionary<string, string> wffmFields)
{
string sourceFile = Path.Combine(@"D:\Sample Template.dotx");
string destinationFile = Path.Combine(@"D:\" + DateTime.Now.ToString("ddMMyyyyhhmmss") + ".docx");
// Don't
continue if the template file name is not found
if (!File.Exists(sourceFile))
{
throw new Exception(message: "TemplateFileName
(" + sourceFile + ") does not exist");
}
// If
the file is a DOTX file convert it to docx
if (sourceFile.ToUpper().EndsWith("DOTX"))
{
RETURN_VAL resultValue = ConvertTemplate(sourceFile,
destinationFile);
if (!resultValue.Value)
{
var result = resultValue;
}
}
else
{
//
Otherwise make a copy of the Word Document to the targetFileName
File.Copy(sourceFile, destinationFile);
}
using (WordprocessingDocument doc = WordprocessingDocument.Open(destinationFile, true))
{
doc.ChangeDocumentType(WordprocessingDocumentType.Document);
string FieldDelimeter = "
MERGEFIELD ";
var document = doc.MainDocumentPart.Document;
foreach (var field in document.Descendants<FieldCode>())
{
var fieldNameStart =
field.Text.LastIndexOf(FieldDelimeter, System.StringComparison.Ordinal);
var fieldname = field.Text.Substring(fieldNameStart
+ FieldDelimeter.Length).Trim();
string newFieldName =
field.Text.Replace(" MERGEFIELD ", "").Replace(" \\*
MERGEFORMAT ", "").Trim();
var splitChars =
newFieldName.Split(new string[] { "\\b" }, StringSplitOptions.RemoveEmptyEntries);
var columnName =
splitChars[0].Trim().Trim(new char[] { '"' });
if (splitChars.Length > 1)
{
var columnDesc = splitChars[1].Trim().Trim(new char[] { '"' });
}
// Go through all of the Run elements and replace the Text
Elements Text Property
foreach (Run run in document.Descendants<Run>())
{
foreach (Text txtFromRun in run.Descendants<Text>().Where(a =>
a.Text.Contains("«" + columnName + "»")))
{
txtFromRun.Text =
wffmFields[columnName];
break;
}
}
}
//
If the Document has settings remove them so the end user doesn't get prompted
to use the data source
DocumentSettingsPart settingsPart = doc.MainDocumentPart.GetPartsOfType<DocumentSettingsPart>().First();
var oxeSettings = settingsPart.Settings.Where(a =>
a.LocalName == "mailMerge").FirstOrDefault();
if (oxeSettings != null)
{
settingsPart.Settings.RemoveChild(oxeSettings);
settingsPart.Settings.Save();
}
doc.MainDocumentPart.Document.Save();
}
}
//
Struct to hold the return value and possible exception
public struct RETURN_VAL
{
public bool Value;
public string Exception;
}
/// <summary>
/// Converts the DOTX to DOCX
/// </summary>
/// <returns>True or False (with an exception) if successful in
converting the document</returns>
private static RETURN_VAL ConvertTemplate(string _templateFileName, string _targetFileName)
{
try
{
MemoryStream msFile = null;
using (Stream sTemplate = File.Open(_templateFileName, FileMode.Open, FileAccess.Read))
{
msFile = new MemoryStream((int)sTemplate.Length);
sTemplate.CopyTo(msFile);
msFile.Position = 0L;
}
using (WordprocessingDocument wpdFile = WordprocessingDocument.Open(msFile, true))
{
wpdFile.ChangeDocumentType(DocumentFormat.OpenXml.WordprocessingDocumentType.Document);
MainDocumentPart docPart
= wpdFile.MainDocumentPart;
docPart.AddExternalRelationship("http://schemas.openxmlformats.org/officeDocument/2006/relationships/attachedTemplate", new System.Uri(_templateFileName, UriKind.RelativeOrAbsolute));
docPart.Document.Save();
}
//
Flush the MemoryStream to the file
File.WriteAllBytes(_targetFileName, msFile.ToArray());
msFile.Close();
return new RETURN_VAL { Value = true };
}
catch (Exception ex)
{
return new RETURN_VAL { Value = false, Exception = "DocumentGeneration::convertTemplate()
- " + ex.ToString() };
}
}
}
}
After executing
this code, my WFFM fields values replace the word mail merge fields as
Sitecore WFFM with Word Mail Merge |
I hope you like this Sitecore tip. Stay tuned for more Sitecore
related articles.
Till that happy Sitecoring
:)