Blog

Blog

Amount in Words in Microsoft Dynamics 365 Business Central

Posted on 25-Jul-2025 by Shrey Chauhan Associate Technical Consultant

💬 Amount in Words in Microsoft Dynamics 365 Business Central

When dealing with financial documents like invoices, payment vouchers, and purchase orders, it's often necessary to express numeric amounts in words. This isn't just for formality—many organizations and legal systems require it to avoid ambiguity or fraud.

That’s where the "Amount in Words" feature in Microsoft Dynamics 365 Business Central becomes handy.

📌 What is "Amount in Words"?

The Amount in Words refers to the textual representation of a numeric currency value. For example:
• Numeric: ₹1,234.56
• In Words: "One Thousand Two Hundred Thirty-Four Rupees and Fifty-Six Paise"

This is often printed at the bottom of cheques, invoices, and legal documents to clearly convey the total payable amount in text form.

🎯 Why is it Useful?

  • ✅ Prevents tampering or fraud (changing “1,000” to “9,000” is easy in numbers, harder in words)
  • ✅ Complies with legal and accounting standards in many countries
  • ✅ Improves clarity for customers and stakeholders
  • ✅ Adds professionalism to printed reports or PDFs

🏗️ How to Use "Amount in Words" in Business Central

✅ Standard (Out-of-the-box) Method

Business Central includes a standard function to convert numbers to words, located in Report 18935 "Check Report".

Here’s how to use it in AL code:


var
    CheckReport: Report "Check Report";
    AmountInWords: Text;
begin
    AmountInWords := GenJnlPostLine.FormatNoText(1234.56, 'INR');
    Message(AmountInWords);
end;
  

This returns:

🗣️ One Thousand Two Hundred Thirty-Four Rupees and Fifty-Six Paise

Parameters:

  • The first parameter is the amount (Decimal)
  • The second is the currency code (e.g., 'USD', 'INR', 'EUR')

This function is localization-aware and works seamlessly in standard reports, including:

  • Sales Invoice
  • Purchase Order
  • Payment Journal

You can bind this result to a label in RDLC or Word layout if you’re building or customizing a report.

🧑💻 Custom "Amount in Words" Function (If You Need More Control)

While the standard method works great, sometimes you may want to customize the output—for example:

  • Show amount without "Paise" or "Cents"
  • Use uppercase text only
  • Add prefix or suffix like "Rupees Only"
  • Support for custom currency formats (e.g., Lakhs/Crores in Indian format)

Here’s a simplified custom function:


codeunit 50101 "Amount in Words"
{
    procedure FormatNoText(var NoText: array[2] of Text[80]; No: Decimal; CurrencyCode: Code[10])
    var
        GLSetup: Record "General Ledger Setup";
        PrintExponent: Boolean;
        DecimalPart: Decimal;
        DecimalInt: Integer;
        Exponent: Integer;
        Hundreds: Integer;
        NoTextIndex: Integer;
        Ones: Integer;
        OnesDec: Integer;
        Tens: Integer;
        TensDec: Integer;
    begin
        Clear(NoText);
        NoTextIndex := 1;

        InitTextVariable();
        InitExponentText(CurrencyCode);
        GLSetup.Get();

        if No < 1 then
            AddToNoText(NoText, NoTextIndex, PrintExponent, Text026Lbl)
        else
            for Exponent := 4 downto 1 do begin
                PrintExponent := false;
                Ones := No div Power(1000, Exponent - 1);
                No := No mod Power(1000, Exponent - 1);

                Hundreds := Ones div 100;
                Tens := (Ones mod 100) div 10;
                Ones := Ones mod 10;

                if Hundreds > 0 then begin
                    if Hundreds in [1 .. 9] then
                        AddToNoText(NoText, NoTextIndex, PrintExponent, OnesText[Hundreds]);
                    AddToNoText(NoText, NoTextIndex, PrintExponent, Text027Lbl); // "Hundred"
                end;

                if Tens >= 2 then begin
                    AddToNoText(NoText, NoTextIndex, PrintExponent, TensText[Tens]);
                    if Ones > 0 then
                        AddToNoText(NoText, NoTextIndex, PrintExponent, OnesText[Ones]);
                end else
                    if (Tens * 10 + Ones) > 0 then
                        AddToNoText(NoText, NoTextIndex, PrintExponent, OnesText[Tens * 10 + Ones]);

                if PrintExponent and (Exponent > 1) then
                    AddToNoText(NoText, NoTextIndex, PrintExponent, ExponentText[Exponent]);
            end;

        if No <> 0 then
            AddToNoText(NoText, NoTextIndex, PrintExponent, Text028Lbl); // "AND"

        DecimalPart := ABS(No - ROUND(No, 1, '<'));
        DecimalInt := ROUND(DecimalPart * 100, 1, '=');
        TensDec := DecimalInt DIV 10;
        OnesDec := DecimalInt MOD 10;

        if TensDec >= 2 then begin
            AddToNoText(NoText, NoTextIndex, PrintExponent, TensText[TensDec]);
            if OnesDec > 0 then
                AddToNoText(NoText, NoTextIndex, PrintExponent, OnesText[OnesDec]);
        end else
            if (TensDec * 10 + OnesDec) > 0 then
                AddToNoText(NoText, NoTextIndex, PrintExponent, OnesText[TensDec * 10 + OnesDec]);

        if DecimalInt > 0 then
            if CurrencyCode = 'INR' then
                AddToNoText(NoText, NoTextIndex, PrintExponent, 'PAISE')
            else
                AddToNoText(NoText, NoTextIndex, PrintExponent, 'CENTS');

        if CurrencyCode <> '' then
            AddToNoText(NoText, NoTextIndex, PrintExponent, 'ONLY');
    end;

    local procedure AddToNoText(var NoText: array[2] of Text; var NoTextIndex: Integer; var PrintExponent: Boolean; AddText: Text[30])
    begin
        PrintExponent := true;

        while StrLen(NoText[NoTextIndex] + ' ' + AddText) > MaxStrLen(NoText[1]) do begin
            NoTextIndex := NoTextIndex + 1;
            if NoTextIndex > ArrayLen(NoText) then
                Error(Text029Lbl, AddText);
        end;

        NoText[NoTextIndex] := DelChr(NoText[NoTextIndex] + ' ' + AddText, '<');
    end;

    procedure InitTextVariable()
    begin
        OnesText[1] := Text032Lbl;
        OnesText[2] := Text033Lbl;
        OnesText[3] := Text034Lbl;
        OnesText[4] := Text035Lbl;
        OnesText[5] := Text036Lbl;
        OnesText[6] := Text037Lbl;
        OnesText[7] := Text038Lbl;
        OnesText[8] := Text039Lbl;
        OnesText[9] := Text040Lbl;
        OnesText[10] := Text041Lbl;
        OnesText[11] := Text042Lbl;
        OnesText[12] := Text043Lbl;
        OnesText[13] := Text044Lbl;
        OnesText[14] := Text045Lbl;
        OnesText[15] := Text046Lbl;
        OnesText[16] := Text047Lbl;
        OnesText[17] := Text048Lbl;
        OnesText[18] := Text049Lbl;
        OnesText[19] := Text050Lbl;

        TensText[1] := '';
        TensText[2] := Text051Lbl;
        TensText[3] := Text052Lbl;
        TensText[4] := Text053Lbl;
        TensText[5] := Text054Lbl;
        TensText[6] := Text055Lbl;
        TensText[7] := Text056Lbl;
        TensText[8] := Text057Lbl;
        TensText[9] := Text058Lbl;
    end;

    local procedure InitExponentText(CurrencyCode: Code[10])
    begin
        Clear(ExponentText);

        if CurrencyCode = 'INR' then begin
            ExponentText[1] := ''; // Ones
            ExponentText[2] := 'THOUSAND';
            ExponentText[3] := 'LAKH';
            ExponentText[4] := 'CRORE';
        end else begin
            ExponentText[1] := ''; // Ones
            ExponentText[2] := Text059Lbl; // THOUSAND
            ExponentText[3] := Text060Lbl; // MILLION
            ExponentText[4] := Text061Lbl; // BILLION
        end;
    end;

    var
        TensText: array[10] of Text[30];
        OnesText: array[20] of Text[30];
        ExponentText: array[5] of Text[30];
        Text032Lbl: Label 'ONE';
        Text033Lbl: Label 'TWO';
        Text034Lbl: Label 'THREE';
        Text035Lbl: Label 'FOUR';
        Text036Lbl: Label 'FIVE';
        Text037Lbl: Label 'SIX';
        Text038Lbl: Label 'SEVEN';
        Text039Lbl: Label 'EIGHT';
        Text040Lbl: Label 'NINE';
        Text041Lbl: Label 'TEN';
        Text042Lbl: Label 'ELEVEN';
        Text043Lbl: Label 'TWELVE';
        Text044Lbl: Label 'THIRTEEN';
        Text045Lbl: Label 'FOURTEEN';
        Text046Lbl: Label 'FIFTEEN';
        Text047Lbl: Label 'SIXTEEN';
        Text048Lbl: Label 'SEVENTEEN';
        Text049Lbl: Label 'EIGHTEEN';
        Text050Lbl: Label 'NINETEEN';
        Text051Lbl: Label 'TWENTY';
        Text052Lbl: Label 'THIRTY';
        Text053Lbl: Label 'FORTY';
        Text054Lbl: Label 'FIFTY';
        Text055Lbl: Label 'SIXTY';
        Text056Lbl: Label 'SEVENTY';
        Text057Lbl: Label 'EIGHTY';
        Text058Lbl: Label 'NINETY';
        Text059Lbl: Label 'THOUSAND';
        Text060Lbl: Label 'MILLION';
        Text061Lbl: Label 'BILLION';
        Text026Lbl: Label 'ZERO';
        Text027Lbl: Label 'HUNDRED';
        Text028Lbl: Label 'AND';
        Text029Lbl: Label '%1 results in a written number that is too long.';
}

  

Note: You can write your own converter or use external libraries/API if you need support for special formatting (like Indian number system: Lakhs/Crores).

✅ Example Results:

Input: 12345678.25 with INR
Output: ONE CRORE TWENTY THREE LAKH FORTY FIVE THOUSAND SIX HUNDRED SEVENTY EIGHT AND TWENTY FIVE PAISE ONLY

Input: 12345678.25 with USD
Output: TWELVE MILLION THREE HUNDRED FORTY FIVE THOUSAND SIX HUNDRED SEVENTY EIGHT AND TWENTY FIVE CENTS ONLY

📄 Where Can You Use "Amount in Words"?

  • Sales Invoices
  • Credit Memos
  • Purchase Invoices
  • Payment Vouchers
  • Cheques
  • Custom Reports
  • Excel/Word exports

🧠 Final Thoughts

The "Amount in Words" feature, though often overlooked, is a crucial detail in any business application that handles monetary values. Business Central 365 provides a clean, standard way to achieve this, but also allows customization for more specific or region-based needs.

Whether you're building compliance-focused reports or simply want to add polish to your documents, implementing amount in words is a small detail with big impact.


Post a Comment

Your email address will not be published. Required fields are marked (*)

Captcha
can't read? refresh

WhatsApp Now