Kwota słownie

Data dodania:
24 lipca 10
Autor:
Łukasz Rutkowski
Kategoria:
Nasza twórczość, PHP

Podczas generowania różnego rodzaju dokumentów, jak choćby blankiety wpłaty pieniędzy, czy faktur, napotykamy się na problem generowania słownej prezentacji kwoty. O ile wypełniając takie rzeczy ręcznie nie jest to trudne oraz oczywiście jeżeli ktoś nie ma problemów z pisownią na przykład “sześćset”(ile to razy widziało się mandaty czy inne rzeczy z napisem “szejset”), o tyle tworząc takie rzeczy, chcemy zautomatyzować jak najwięcej procesów. Głupstwem byłoby tworzenie ręcznego wprowadzania kwoty słownie, więc w każdym projekcie dochodzi się do zagadnienia generowania słownej reprezentacji kwoty. Od razu spieszę z pomocą. Mianowicie: stworzyłem klasę, która pozwala wygenerować ten zapis aż do kwoty 999 999 999 zł 99 gr. W Internecie można spotkać się z klasami do bilionów, trylionów itd., lecz powiedzmy sobie szczerze: kto to wykorzysta? Są to sporadyczne przypadki, gdzie już programista może się minimalnie bardziej zmęczyć i dopisać obsługę większych kwot, co przy już gotowym kodzie tysięcy i milionów, byłoby kwestią pięciu minut.

Klasa AmountInWords

Poniżej zamieszczam kod mojej klasy, która w bardzo prosty sposób umożliwi Ci wygenerowanie słownego zapisu kwoty. Bez większych przeszkód możesz jej używać w projektach komercyjnych, gdyż wybrana przeze mnie licencja na to w pełni zezwala. Wystarczy mi to, że pozostawisz komentarz, który znajduje się nad kodem klasy.

/**
*
* @copyright (c) 2010 Łukasz Rutkowski
* @license http://creativecommons.org/licenses/by/3.0/pl/ Creative Commons Uznanie autorstwa 3.0
*
*/
 
class AmountInWords {
    private static $units = array(
        'zero',
        'jeden',
        'dwa',
        'trzy',
        'cztery',
        'pięć',
        'sześć',
        'siedem',
        'osiem',
        'dziewięć',
        'dziesięć',
        'jedenaście',
        'dwanaście',
        'trzynaście',
        'czternaście',
        'piętnaście',
        'szesnaście',
        'siedemnaście',
        'osiemnaście',
        'dziewiętnaście'
    );
    private static $tens = array(
        '',
        'dziesięć',
        'dwadzieścia',
        'trzydzieści',
        'czterdzieści',
        'pięćdziesiąt',
        'sześćdziesiąt',
        'siedemdziesiąt',
        'osiemdziesiąt',
        'dziewięćdziesiąt'
    );
    private static $hundreds = array(
        '',
        'sto',
        'dwieście',
        'trzysta',
        'czterysta',
        'pięćset',
        'sześćset',
        'siedemset',
        'osiemset',
        'dziewięćset'
    );
 
    private static $thousands = array(
        'tysiąc',
        'tysiące',
        'tysięcy'
    );
 
    private static $millions = array(
        'milion',
        'miliony',
        'milionów'
    );
 
    public static function getGr($amount)
    {
        $gr = ( $amount - floor($amount) ) * 100;
        return $gr;
    }
 
    public static function getZl($amount)
    {
        $str = '';
 
        $zl = floor($amount);
        $len = strlen($zl);
        if($len >= 7) {
            $million = substr($zl, -7, 1);
            $million2 = substr($zl, -7, 1);
            if($len >= 5) {
                $million = substr($zl, -8, 1).$million;
            }
            if($len >= 6) {
                $million = substr($zl, -9, 1).$million;
            }
            if($million != 1) {
                $str .= self::getZl((float)$million).' ';
            }
            if($million2 == 1) {
                $str .= self::$millions[0].' ';
            } elseif($million2 >= 2 AND $million2 <= 4) {
                $str .= self::$millions[1].' ';
            } else {
                $str .= self::$millions[2].' ';
            }
        }
 
        if($len >= 4) {
            $thousand = substr($zl, -4, 1);
            $thousand2 = substr($zl, -4, 1);
            if($len >= 5) {
                $thousand = substr($zl, -5, 1).$thousand;
            }
            if($len >= 6) {
                $thousand = substr($zl, -6, 1).$thousand;
            }
            if($thousand > 1) {
                $str .= self::getZl((float)$thousand).' ';
            }
            if($thousand2 == 1) {
                $str .= self::$thousands[0].' ';
            } elseif($thousand2 >= 2 AND $thousand2 <= 4) {
                $str .= self::$thousands[1].' ';
            } elseif($thousand2 != 0) {
                $str .= self::$thousands[2].' ';
            }
        }
 
        if($len >= 3) {
            $hundreds = substr($zl, -3, 1);
            if($hundreds != 0) {
                $str .= self::$hundreds[$hundreds].' ';
            }
        }
        if($len >= 1) {
            if($len == 1) {
                $to99 = substr($zl, -1, 1);
            } else {
                $to99 = substr($zl, -2, 2);
            }
            if($to99 < 20) {
                if(substr($to99, 0, 1) == '0') {
                    $to99 = substr($to99, 1, 1);
                }
                if($to99 != 0) {
                    $str .= self::$units[$to99].' ';
                }
            } else {
                $ten = substr($to99, 0, 1);
                $str .= self::$tens[$ten].' ';
 
                $unit = substr($to99, 1, 2);
                if($unit != '0') {
                    $str .= ' '.self::$units[$unit].' ';
                }
            }
        }
        if($zl == 0) {
            $str .= self::$units[0].' ';
        }
        return $str;
    }
 
    public static function get($amount)
    {
        $str = self::getZl($amount).'zł '.self::getGr($amount).'/100';
        return $str;
    }
}

Używanie

Zastosowanie powyższej klasy w praktyce jest banalnie proste. Najbardziej banalnym odwołaniem do niej jest:

AmountInWords::get(212.59);

Wywołana metoda zwróci wtedy kwotę słownie w postaci:

dwieście dwanaście zł 59/100

Czyli w najpowszechniej stosowanym formacie na blankietach, fakturach i innych “papierkach”. W przypadku, kiedy chcemy sobie to wyświetlić inaczej, nie ma największego problemu i wystarczy, że manualnie wykorzystamy dwie metody: getZl() i getGr(). Pierwsza zwróci samo:

dwieście dwanaście

Zaś druga:

59

Nic nie stoi również na przeszkodzie, aby grosze przekazać do funkcji getZl() i również wyświetlić je w postaci słownej. Czas na przykład:

echo AmountInWords::getZl(212.59).' złoty oraz '.AmountInWords::getZl(59).' groszy';

Wyświetli to:

dwieście dwanaście złoty oraz pięćdziesiąt dziewięć groszy

Resztę pozostawiam Twojej wyobraźni. Dodam tylko, że nic nie stoi na przeszkodzie, aby wykorzystać powyższą klasę do generowania słownych zapisów liczb innego typu.

~Łukasz Rutkowski