back to top

Creating Custom Macros To Format Values in Word Printables for Creatio (formerly bpm’online)

In Word printables for Creatio, it’s possible to create all sorts of custom macros to query and add related data, bring in values such as the current user, or just to format values. This article will look at creating a custom macro to format currency values in a Word printable, however the concepts are the same for any type of macro you’d like to create for Creatio.

The way a custom Macro for Creatio works is, you create a Source Code schema with a class that implements the IExpressionConverter interface. You define an attribute, which will be your macro’s name. Then, you can add that macro name to any merge field and when the printable is run, the value for the merge field will be passed to your code, you can do whatever you want with it, such as, simply format it, or use it to run a query and look up some other data to return, etc.

First, let’s create the macro. Again, our example will create a macro that just receives a currency value, formats it as money, then returns the formatted value to display in the Word doc. Add a new Source Code schema, give it a name of “UsrMoneyConverter” and add the following code:

namespace Terrasoft.Configuration
{
    using System;
    using Terrasoft.Common;
    using Terrasoft.Core;
    using Terrasoft.Core.DB;
    using Terrasoft.Core.Entities;
    using Terrasoft.Core.Packages;
    using Terrasoft.Core.Factories;
    using System.Globalization;
     
    [ExpressionConverterAttribute("Money")]
    public class UsrMoneyConverter : IExpressionConverter
    {
        public string Evaluate(object value, string arguments = "") 
        {
            var result = string.Empty;
            if (value != null)
            {
                result = value.ToString();
                double currency;
                if (Double.TryParse(result, out currency))
                {
                    result = currency.ToString("C", new CultureInfo("en-US"));
                }
            }
            return result;
        }
    }
}

Notice the ExpressionConverterAttribute attribute on the class, it is defining the macro name as “Money” – this is the name of our macro and what we’ll refer to it as to use it. The code simply receives a value, converts it to a double to ensure it’s a currency value, then returns the formatted value.

To use it, we’ll need to add it to a merge field in a Word printable. In the report setup of a Word printable, add any currency field. Then click the pencil icon to edit it:

Then add [#Money#] at the end of the title. Basically, leave the title as it is, just paste that at the end. We’re using “Money” since that is what our macro is called. You’d obviously use [#MacroName#] where MacroName is the name of your macro, meaning the value specified in the ExpressionConverterAttribute attribute in your code. It will look like this:

Now, you can drag that into the Word document and when that merge field is processed, it will pass the value to your code for the custom Money macro and the returned value will be what displays there in the Word doc.

While this sample was to simply format a value, we could use this same concept for other purposes as well. For example, you could add an Id for a record as a merge field, then when the Id is passed into your macro, you run a query to retrieve some other data and return that instead.

Note, if you need to use a UserConnection in the macro to retrieve data from elsewhere, you can use the following:

var userConnection = (UserConnection)System.Web.HttpContext.Current.Session["UserConnection"];

You can read more about creating custom macros in the Academy

Contact Customer FX for your CRM project
We let our expertise speak for itself - let us know how our all-star team can help on your CRM project
About the Author
Ryan Farley
Ryan Farleyhttps://customerfx.com/article/author/ryanfarley/
Ryan Farley is the Director of Development for Customer FX and creator of slxdeveloper.com. He's been blogging regularly about SalesLogix, now Infor CRM, since 2001 and believes in sharing with the community. His new passion for CRM is Creatio, formerly bpm'online. He loves C#, Javascript, web development, open source, and Linux. He also loves his hobby as an amateur filmmaker.

23 COMMENTS

  1. Hi Ryan

    I have tried to replicate the same which you have mentioned above but my report is blank when I run it.

    Regards
    Sivanesan

  2. Dear Ryan,

    Is there a possibility to show a table based on a field value? I guest it might use features of Word to make it happen.

    Would you please give some insights about it?

    • I don’t know of any way to return the proper Word or RTF codes for a table from a macro. I don’t believe it’s possible.

      What I typically do is create a database view that contains the logic for the table. Then, create an object for that view and expose that in the printable. This is a common way I include tables in printables that contain more complex logic or custom data of some kind.

      Ryan

  3. I’m trying to understand what/how the “arguments” parameter of the Evaluate(object value, string arguments = “”) function is used. No luck so far… can someone help? 🙂

    • Let’s say you create a macro called “DueDate”. The macro will get passed a date value. If the date has not yet passed, the macro returns the date back to the printable. If the date has passed it returns the text passed in the arguments. In this scenario, the date is passed as the “value” argument, and the text it will return if the date has passed is returned as the argument.

      To use this macro it would look like this:

      SomeDateField[#DueDate|Past Due#]

      The “value” and the “arguments” params are separated by a | character. In the above, if the date value in SomeDateField has not yet passed, the date value will appear in the doc. If it has passed, the value “Past Due” will appear instead.

      In the macro code, the string, in this case, “Past Due” will be passed in as the argument. You could also use something else like:

      SomeDateField[#DueDate|Completed#]

      And in this case the string “Completed” will be passed as the argument. For the arguments param, it is usually a good idea to use a default value that is used in case no additional arguments were passed.

      Hope this helps

      Ryan

    • Yes, that helps 🙂 10x a lot. Also I was finally able to find this information but in an older Creatio development guide (for version 7.16). For some reason they didn’t elaborate this part in 8.1 documentation.

  4. Hello. Is it possible to read data from other fields on the page? For example, to build a particular string from different fields based on the received value. Tnx.

  5. Any idea if it’s possible to use multiple macros for the same field? e.g. if I have one for converting into currency format and another for conditionally blanking a field?

    • Yes, that is possible, however could complicate the macro itself. To do that you’d need to pass some value in the arguments parameter that indicated what action to take.

      For example:
      SomeMoneyField[#UsrMyMacro|FormatCurrency#]
      Or
      SomeTextField[#UsrMyMacro|ConditionalBlank#]

      Then in the macro itself you’d check the arguments value to determine which action to take on the value.
      Ryan

    • Sorry, I wasn’t very clear on that, my bad! What I mean is apply one fairly generic macro and then apply another one to the output of the first one, both for a single output “field” that’s mapped into the Word document. I ask as it would allow having a set of more generic macros that could be strung together for an output field, rather than having the same logic in many macros. Sort of like piping the macros together.

    • Hi Harvey,
      Still not sure I follow. However, I think (maybe?) what you’re after is basically calling one macro from another macro? So the end result is both macros, but you only had to add one to the doc?

      If so, then yes, you can do that. If I had a general purpose macro, then wanted to call the “Money” macro defined in this article from that general purpose macro, I’d just instantiate the class and call it directly:

      var moneyMacro = new Terrasoft.Configuration.UsrMoneyConverter();
      result = moneyMacro.Evaluate(result);

      Is that what you’re after?
      Ryan

    • Hi Ryan, it’s more that I might have a collection of general purpose macros and decide I want to apply 2+ of them to a field in succession (so using an imaginary syntax in the Printable, SomeMoneyField[#Money#][#ConditionalBlank|SomeCondition#] ) rather than pre-baking the progression of one followed by another into the macro C# code.

      I suppose one way of doing that might be to use the code you suggested there to define some kind of “pipeline” macro that knows about all the potential macros that might be chained together and pass each of the names of the macros you want to use as arguments into that “pipeline” macro, but that would require updating the pipeline macro with any new/modified macros, and if those pipelined macros had arguments of their own the syntax & interpretation would start to get a little bit wild! Something like SomeMoneyField[#UsrPipelineMacro|FormatCurrency>ConditionalBlank|SomeCondition#] for the above.

    • I don’t believe that is possible Harvey (although I’ve never really tried chaining them together). I would assume the only way is to do it in the macro code, I doubt it works to chain them together as macro fields in the doc (but again, never tried)

    • Turns out it actually is possible OOTB which is nice! You just have to put the converters one after another in the mapping, so like SomeMoneyField[#Money#][#ConditionalBlank#] and then output of the first gets passed into the 2nd.

    • Also, it sounds like the order is → and not ←, right?

      So for this:
      SomeMoneyField[#Money#][#ConditionalBlank#]

      It would first do [#Money#] then use the result to pass to [#ConditionalBlank#] second, correct?

    • Yes, left to right, so in the example [#Money#] is run and its output passed into [#ConditionalBlank#] exactly.

    • I saw that it might work from the ExpressionConverterHelper code and tested it and it does indeed work, fortunately.

LEAVE A REPLY

Please enter your comment!
Please enter your name here

Building AI-Powered Workflows in Creatio Without Writing Code

See how Creatio can combine AI with no-code business processes to qualify, summarize, and route incoming leads while keeping your existing business rules and human oversight in place.

AI Readiness Checklist for CRM Teams: Is Your CRM System Ready for AI?

Before using AI in Creatio, make sure your CRM data, users, processes, and automation foundation are ready. Use this practical AI readiness checklist for CRM teams.

Build Your Creatio AI Skills with the 2026 AI Summer Program

Join Creatio’s free 2026 AI Summer Program to learn how to identify, build, deploy, and manage AI agents.

Creatio 10x Is Coming: Join the Webinar to Explore the Future of AI-Native CRM

Learn what's new in Creatio 10x and how AI-native CRM, agentic AI, and no-code automation are shaping the future of customer relationship management. Join the upcoming webinar and discover what's next.

Creatio Unlimited Pricing Explained: AI Packages, Costs, Pros & Cons

Learn what Creatio’s new Unlimited pricing model includes, what it doesn’t include, how AI Action packages work, and the pros and cons for businesses evaluating Creatio.

Related Articles

Building AI-Powered Workflows in Creatio Without Writing Code

See how Creatio can combine AI with no-code business processes to qualify, summarize, and route incoming leads while keeping your existing business rules and human oversight in place.

AI Readiness Checklist for CRM Teams: Is Your CRM System Ready for AI?

Before using AI in Creatio, make sure your CRM data, users, processes, and automation foundation are ready. Use this practical AI readiness checklist for CRM teams.

Build Your Creatio AI Skills with the 2026 AI Summer Program

Join Creatio’s free 2026 AI Summer Program to learn how to identify, build, deploy, and manage AI agents.

Creatio 10x Is Coming: Join the Webinar to Explore the Future of AI-Native CRM

Learn what's new in Creatio 10x and how AI-native CRM, agentic AI, and no-code automation are shaping the future of customer relationship management. Join the upcoming webinar and discover what's next.

Related Videos