Javenue logo

Javenue

Программирование на Java

Информационные технологии

Запись денежной суммы словами - Java утилита

Все же в финансовой сфере достаточно часто попадаются интересные вещи, что бы там не говорили.

Когда-то заказчики поставили перед нашей командой следующую задачу: на чеке необходмо отображать сумму не только цифрами, но и словами. После непродолжительного гугления был обнаружен небольшой класс, написанный на Java еще в 2003 году (к сожалению оригинал больше найти не получается). Код был немного устаревшим и содержал пару мелких ошибок. Тем не менее, за короткий промежуток времени код удалось исправить и успешно внедрить в проект, за что автору кода большое спасибо.

Сейчас дошли руки переписать этот класс (теперь он называется AmountInWords), избавиться от дублирования кода и слегка расширить функциональные возможности.

В этой статье я приведу основные варианты использования класса, а именно:

  • непосредственно использование класса для форматирования сумм;
  • добавление новых валют;
  • интеграция класса в уже написанную систему.

Начнем...

Исходный код класса можно найти здесь - AmountInWords.java

Использование класса AmountInWords

Грубо говоря, в классе есть только один метод для форматирования - format (без кэпа не обошлось). Метод принимает на вход сумму в копейках и валюту, для которых нужно получить строковое представление. Примеры:

System.out.println(AmountInWords.format(1234567890L, AmountInWords.UAH));
System.out.println(AmountInWords.format(987654321L, AmountInWords.RUB));
System.out.println(AmountInWords.format(100000100101111L, AmountInWords.USD));
System.out.println(AmountInWords.format(123321123321L, AmountInWords.EUR));

Код напечатает:

двенадцать миллионов триста сорок пять тысяч шестьсот семьдесят восемь гривен девяносто копеек 
девять миллионов восемьсот семьдесят шесть тысяч пятьсот сорок три рубля двадцать одна копейка 
один триллион один миллион одна тысяча одиннадцать долларов одиннадцать центов 
один миллиард двести тридцать три миллиона двести одиннадцать тысяч двести тридцать три евро двадцать один евроцент

Константа AmountInWords.UAH имеет тип AmountInWords.Currency. Кроме гривны (UAH) еще предопределены такие валюты как доллар (USD), евро (EUR) и рубль (RUB). В классе Currency кроме числового и буквенного кодов валюты еще содержится и вся необходимая морфология.

Метод бросает UnsupportedOperationException если сумма по модулю больше "1015 - 1". Этого должно хватить, даже если вы напечатаете на чеке величину мирового валового продукта в гривне.

Для упрощения вызова метода format есть его перегруженная версия, которая принимает только сумму, а в качестве валюты берет валюту по-умолчанию. Устновить валюту по-умолчанию можно с помощью метода setDefaultCurrency.

Добавление (регистрация) новых валют

Для добавления новой валюты необходимо создать экземпляр класса Currency и зарегистрировать его с помощью метода addCurrency. Чтобы все работало корректно, нужно проинициализировать 8 полей, которые используются для морфологии. На всякий случай при добавлении новой валюты выполняется небольшая валидация. Это поможет избежать некоторых частых ошибок. Пример (для простоты допустим, что сэн всегда во множественном числе):

        Currency yen = new Currency(392, "JPY") {{
            oneInteger = "иена";
            twoIntegers = "иены";
            fiveIntegers = "иен";
            integerSex = Sex.FEMALE;
            oneFraction = "сэн";
            twoFractions = "сэн";
            fiveFractions = "сэн";
            fractionSex = Sex.MALE;
        }};
        AmountInWords.addCurrency(yen);
        System.out.println(AmountInWords.format(2345678, yen));
        System.out.println(AmountInWords.format(110111, yen));
        System.out.println(AmountInWords.format(220222, yen));

Вывод на консоль будет таким:

двадцать три тысячи четыреста пятьдесят шесть иен семьдесят восемь сэн 
одна тысяча сто одна иена одиннадцать сэн 
две тысячи двести две иены двадцать два сэн 

Вопросы интеграции класса

В принципе, после копирования кода в ваш проект, класс Currency можно вынести на upper-level, немного допилить под свои нужды и использовать по назначению. Но если у вас в системе уже есть своя сущность Currency для валют - не беда. Для интеграции достаточно предоставить имплементацию интерфейса AmountInWords.CurrencyMapping содержащего один простой метод getCurrency. Пример:

    public static void main(String[] args) {
        class TheCurrency {
            Integer code;
            TheCurrency(Integer code) {
                this.code = code;
            }
        }

        AmountInWords.setCurrencyMapping(
            new CurrencyMapping<TheCurrency>() {
                public Currency getCurrency(TheCurrency currency) {
                    return AmountInWords.Currency.byCode(currency.code);
                }
            }
        );

        TheCurrency uah = new TheCurrency(980);
        System.out.println(AmountInWords.format(91, uah));
    }

Код напечатает: ноль гривен девяносто одна копейка

Сумма словами поддерживается только на одном языке. Поддержка многоязычности со временем появится. Но возможно вы уже сейчас захотите использовать класс и вам как на зло понадобится другой славянский язык (мы, например, используем украинский). Для вашего удобства я вынес все числительные в список констант, который находится в конце файла. Достаточно перевести их на нужный вам язык и все будет работать.

Так вот незаметно прошел практически весь день... Но, надеюсь, мои труды кому-нибудь пригодятся. До скорых встреч.

P.S. Тестами еще не все покрыл. Как допишу - обязательно выложу. Если вдруг найдете опечатку или ошибку в коде, напишите о них, пожалуйста, в комментариях. Спасибо.



Комментариев: 1

  Выйти

  * для публикации комментариев нужно  

AK-47:

Ваш прекрасный код получил вечную жизнь. Используется в образовательный целях в Одной_Очень_Крупной_Аутсортинговой_Компании_)

опечатка в названии oneInteger = ONE_UAH_INEGER;

хотя это не принципиально

с наилучшими пожеланиями, стажер Одной_Очень_Крупной_Аутсортинговой_Компании.