Korisne JavaScript biblioteke za poslovni software u nas Srba

2378867408_4cc90791d6Prilikom razvoja softvera za poslovnu upotrebu posebna pažnja se obraća na validiranje podataka prilikom unosa. Kako je web sve prisutnija platforma za razvoj ovakvog tipa softvera jedan od načina za validaciju unosa je svakako javascript, odnosno client-side validacija. Ovakav vid validacije je brži i „jeftiniji“ obzirom da nema slanja suvišnih zahteva ka web serveru, no ne treba se u potpunosti osloniti na ovakav vid validacije i zapostaviti serversku stranu ali o tome možda neki drugi put.

Najčešći podaci koje je potrebno validirati u poslovnom softveru su neki od identifikacionih podataka o osobi, firmi, neki poziv na broj na nalogu za plaćanje, broj računa u banci i sl.

Validacija JMBG-a

Osnovni podatak za identifikaciju osobe u Srbiji je JMBG (jedinstveni matični broj građana) (a i u republikama bivše SFRJ, mada ga Hrvati napuštaju od 2009. godine uvođenjem OIB-a (osobnog identifikacionog broja)) . Ovaj broj u sebi sadrži 13 cifara koje nam mogu mnogo toga reći od datuma rođenja, preko pola osobe, regiona u kom je nosilac broja rođen, do rednog broja rođenja u danu (odnosi se na dan, region i pol).

Primer JMBG-a:

DD MM GGG RR BBB K

DD – dan rođenja, MM – mesec rođenja, GGG – zadnje tri cifre godine rođenja

RR – region rođenja ili prebivališta

BBB – jedinstveni broj, redni broj rođenja (000-499 – muški, 500-999 – ženski)

K – kontrolna cifra

Kontrolni broj se izračunava sledećom formulom (brojeve iz JMBG-a ću prikazati redom kao b1, b2… b12):

K = 11 - ((7 x (b1 + b7)
         + 6 x (b2 + b8)
         + 5 x (b3 + b9)
         + 4 x (b4 + b10)
         + 3 x (b5 + b11)
         + 2 x (b6 + b12)) % 11)

Kako kontrolni broj mora biti jednocifren kao problem ostaju vrednosti 10 i 11. Na internetu postoje razni predlozi kako handleovati ove vrednosti (pretvoriti ih u 0, oduzeti 10) ali ispravan način je da se 11 pretvara u 0, a 10 je “X” odnosno nedozvoljena vrednost (u ovom slučaju se veštački uvećavao redni broj rođenja BBB kako bi se izbegla vrednost 10).

Postoje i matični brojevi koji nemaju ispravnu kontrolnu cifru. To su matični brojevi dodeljeni nerezidentima (licima na privremenom boravku u zemlji, tzv. gastarbeiter-ima u Srbiji) i oni se prepoznaju po broju regiona (60 ili 66).

Interpretacija prethodno napisanog u JavaScript-u bi izgledala ovako (ovo je samo deo veće biblioteke pa sam code snippet neće raditi kao takav):

dataValidator.prototype.validanJMBG = function (jmbg) {
   if (typeof jmbg !== "undefined" && jmbg !== null &&
      jmbg.length === 13 && dataValidator.prototype.validanBroj(jmbg)) {
      var dan = parseInt(jmbg.substring(0, 2), 10);
      var mesec = parseInt(jmbg.substring(2, 4), 10) - 1;
      var godina = parseInt("2" + jmbg.substring(4, 7),10);
      if (dataValidator.prototype.validanDatum(new Date(godina, mesec, dan))) {
         return /^60|66$/.test(jmbg.substring(7, 9)) ||
            parseInt(jmbg.charAt(12), 10) === mod11(jmbg.substring(0, 12),
               function (kb) { return kb === 11 ? 0 : ((kb === 10) ? "X" : kb); });
      }
   }
   return false;
};

function mod11(br, dodatni_uslov) {
   var kb = 0;
   for (var i = br.length - 1, mnozilac = 2; i >= 0; i--) {
      kb += parseInt(br.charAt(i), 10) * mnozilac;
      mnozilac = mnozilac === 7 ? 2 : mnozilac + 1;
   }
   kb = 11 - (kb % 11);
   return (typeof dodatni_uslov === "undefined") ? kb : dodatni_uslov(kb);
}

Kao što se može videti iz primera potencijalne dvocifrene vrednosti obrađujemo callback funkcijom. Funkcija mod11 je interna funkcija veće biblioteke i služi, osim za validaciju JMBG-a, za validaciju matičnog broja pravnog lica ili preduzetničke radnje kao i za računanje kontrolnog broja za plaćanje npr. INFOSTAN JKP još uvek koristi model 11 na svojim uplatnicama.

U pomenutoj biblioteci se nalazi ne samo validator za JMBG već i kompletan parser svih podataka iz JMBG-a. Biblioteka je open source i nalazi se na GitHub-u. Projekat sadrži demo stranicu sa svim funkcionalnostima i test case-ovima (korišćen je QUnit).

Validacija matičnog broja pravnog lica

Matični broj pravnog lica odnosno preduzetničke radnje ima 8 cifara gde je poslednja cifra kontrolni broj po modelu 11. Kontrolna cifra se računa na isti način kao i za JMBG sa različitom obradom dvocifrenog slučaja (ovde se 10 i 11 pretvaraju u 0).

U sledećem JavaScript kodu opet pozivamo funkciju mod11 samo menjamo callback funkciju za obradu dvocifrenih rezultata:

dataValidator.prototype.validanMB = function (mb) {
   return mb.length === 8 &&
      dataValidator.prototype.validanBroj(mb) &&
      parseInt(mb.charAt(7), 10) === mod11(mb.substring(0, 7),
         function (kb) { return kb > 9 ? 0 : kb; });
};

Validacija PIB-a

PIB ili poreski identifikacioni broj je jedan od identifikacionih podataka pravnog lica. JavaScript za validaciju PIB-a bi izgledao ovako:

dataValidator.prototype.validanPIB = function (pib) {
   if (pib.length === 9 && dataValidator.prototype.validanBroj(pib)) {
      var suma = 10;
      for (var i = 0; i < 8; i++) {
         suma = (suma + parseInt(pib.charAt(i), 10)) % 10;
         suma = (suma === 0 ? 10 : suma) * 2 % 11;
      }
      suma = (11 - suma) % 10;
      return parseInt(pib.charAt(8), 10) === suma;
   }
   return false;
};

Kontrolni broj po modelu 97

Model 97 se koristi za izračunavanje kontrolnog broja za naloge za plaćanje npr.obavezan je za uplatu javnih prihoda (Poreska uprava) a može se koristiti i za druge potrebe, za izračunavanje kontrolne cifre kod računa u domaćem platnom prometu (račun se sastoji iz tri grupe cifara BBB-PPPPPPPPPPPPP-KK gde je BBB jedinstveni kod banke npr. 265 – Raiffeisen Bank, PPP… – 13 cifara je jedinstveni broj partije u okviru banke – u kratkom zapisu se mogu izuzeti vodeće nule, KK predstavlja kontrolni broj po modelu 97).

Kontrolna cifra se računa sledećom formulom (za primer koristimo br koji predstavlja numerički niz):

K = 98 - ((br x 100) % 97)

Interpretacija ove formule u JavaScript-u je drugačija jer moduo 97 nije davao tačan rezultat u slučaju velikih numeričkih nizova!!!

function mod97(br) {
   var kb = 0, os = 100;
   for (var x = br.length - 1; x >= 0; x--) {
      kb = (kb + (os * parseInt(br.charAt(x), 10))) % 97;
      os = (os * 10) % 97;
   }
   kb = 98 - kb;
   return kb;
}

Ovu funkciju smo iskoristili za praktičnu primenu na sledeći način. Kao što se može videti iz primera ispod validacija kontrolnog broja prima i callback funkciju kojoj predaje niz validacionih grešaka ukoliko ih ima:

dataValidator.prototype.validanMod97 = function (broj, validation_error_callback) {
   if (typeof validation_error_callback !== "undefined") {
      var validation_errors = [];
      if (broj.length <= 2)
         validation_errors.push("Nevalidna dužina broja");
      for (var i = 0; i < broj.length; i++) {
         var validno = false;
         var slovo = broj.charAt(i);
         if (slovoUBroj(slovo) !== null) validno = true;
         else validation_errors.push("Nevalidan znak: (\'" + slovo + "\') na poziciji " + (i + 1).toString());
      }
      if (validation_errors.length !== 0) validation_error_callback(validation_errors);
   }
   return dataValidator.prototype.kontrolniBrojMod97(broj.substring(2)) === broj.substring(0, 2);
};
dataValidator.prototype.kontrolniBrojMod97 = function (broj) {
   if (typeof broj === "undefined" || broj === null || broj === "") return null;
   var zakontrolu = "";
   for (var i = 0; i < broj.length; i++) {
      var vrednost = slovoUBroj(broj.charAt(i));
      if (vrednost === null) return null;
      else zakontrolu += vrednost.toString();
   }
   if (dataValidator.prototype.validanBroj(zakontrolu)) {
      var rez = mod97(zakontrolu);
      return rez.length === 1 ? rez = "0" + rez.toString() : rez.toString();
   }
   else return null;
};

Kako se u kontrolnim brojevima za uplatu poreza mogu naći i slova sledeća funkcija i JSON nam rešavaju problem prevođenja vrednosti:

function slovoUBroj(slovo) {
   return slovo === "-" ? "" :
      ((dataValidator.prototype.validanBroj(slovo)) ? slovo : (_slova_za_kontrolni_broj[slovo] || null));
}
var _slova_za_kontrolni_broj = {
   "A": 10, "B": 11, "C": 12, "D": 13, "E": 14, "F": 15, "G": 16, "H": 17, "I": 18, "J": 19,
   "K": 20, "L": 21, "M": 22, "N": 23, "O": 24, "P": 25, "Q": 26, "R": 27, "S": 28, "T": 29,
   "U": 30, "V": 31, "W": 32, "X": 33, "Y": 34, "Z": 35
};

Jedan jezik a dva pisma: Ћирилица vs latinica

Svi mi koji smo razvijali softver za razmenu podataka sa državnim institucijama drage nam majke Srbije nailazili smo na spojeve nespojivog. Podaci iz lične karte su nam “ograničeni” na svega dva pisma, isto je sa podacima iz Agencije za privredne registre… no da ne nabrajam. Činjenica je da se susrećemo sa mešavinom dva pisma i da nam često zatreba konverzija iz jednog u друго:

var dataConvert = (function () {
   "use strict";
   function dataConvert() { }
   dataConvert.prototype.cir2Lat = function (zapromenu) {
      var rez = "";
      for (var i = 0; i < zapromenu.length; i++) {
          var slovo = zapromenu.charAt(i);
          rez += convert(slovo, _cir2lat);
      }
      return rez;
   };
   dataConvert.prototype.lat2Cir = function (zapromenu) {
      var rez = "";
      for (var i = 0; i < zapromenu.length; i++) {
         var slovo = zapromenu.charAt(i);
         var sledece = zapromenu.charAt(i + 1);
         if (typeof sledece !== "undefined" && sledece !== null)
            if (/^lj|Lj|LJ|nj|Nj|NJ|dž|Dž|DŽ$/.test(slovo + sledece)) {
               slovo += sledece;
               i++;
            }
         rez += convert(slovo, _lat2cir);
      }
      return rez;
   };
   function convert(slovo, recnik) {
      return recnik[slovo] || slovo;
   }
   var _cir2lat = {
      //mala slova
      "а": "a", "б": "b", "в": "v", "г": "g", "д": "d", "ђ": "đ", "е": "e", "ж": "ž", "з": "z", "и": "i",
      "ј": "j", "к": "k", "л": "l", "љ": "lj", "м": "m", "н": "n", "њ": "nj", "о": "o", "п": "p", "р": "r",
      "с": "s", "т": "t", "ћ": "ć", "у": "u", "ф": "f", "х": "h", "ц": "c", "ч": "č", "џ": "dž", "ш": "š",
      //velika slova
      "А": "A", "Б": "B", "В": "V", "Г": "G", "Д": "D", "Ђ": "Đ", "Е": "E", "Ж": "Ž", "З": "Z", "И": "I",
      "Ј": "J", "К": "K", "Л": "L", "Љ": "LJ", "М": "M", "Н": "N", "Њ": "NJ", "О": "O", "П": "P", "Р": "R",
      "С": "S", "Т": "T", "Ћ": "Ć", "У": "U", "Ф": "F", "Х": "H", "Ц": "C", "Ч": "Č", "Џ": "DŽ", "Ш": "Š"
   };
   var _lat2cir = {
      //mala slova
      "a": "а", "b": "б", "v": "в", "g": "г", "d": "д", "đ": "ђ", "e": "е", "ž": "ж", "z": "з", "i": "и",
      "j": "ј", "k": "к", "l": "л", "lj": "љ", "m": "м", "n": "н", "nj": "њ", "o": "о", "p": "п", "r": "р",
      "s": "с", "t": "т", "ć": "ћ", "u": "у", "f": "ф", "h": "х", "c": "ц", "č": "ч", "dž": "џ", "š": "ш",
      //velika slova
      "A": "А", "B": "Б", "V": "В", "G": "Г", "D": "Д", "Đ": "Ђ", "E": "Е", "Ž": "Ж", "Z": "З", "I": "И",
      "J": "Ј", "K": "К", "L": "Л", "LJ": "Љ", "Lj": "Љ", "M": "М", "N": "Н", "NJ": "Њ", "Nj": "Њ", "O": "О", "P": "П", "R": "Р",
      "S": "С", "T": "Т", "Ć": "Ћ", "U": "У", "F": "Ф", "H": "Х", "C": "Ц", "Č": "Ч", "DŽ": "Џ", "Dž": "Џ", "Š": "Ш"
   };
   return dataConvert;
})();

Zaključak

Kako JavaScript postaje sve popularniji jezik bilo bi lepo da ovakvih biblioteka u budućnosti bude više. Nadam se da će ovaj projekat rešiti poneki problem i naći svoju primenu u nekoj od vaših budućih aplikacija.

Za one koji su propustili link ka projektu: draganjovanovic1/JSTools ili možete preuzeti trenutnu verziju: ovde

Postavljena je i demo stranica: JSTools

Pages:
  1. Poštovani,
    Da li znate tačan obrazac za računanje MB firme?

    • Poštovani,

      Imate objašnjenje i kod u pasusu Validacija matičnog broja pravnog lica.

      Ako je potrebno neko dodatno objašnjenje pitajte.

      • Hvala :) Možda se nisam dobro izrazio… Ako sam dobro shvatio, prvih sedam cifara su nasumične i jedinstvene, dok je osma cifra kontrolni broj (mod11)?

        • Upravo tako. Da li su stvarno nasumične ili imaju neki red dodeljivanja ne bih mogao da tvrdim ali bi moralo biti da su jedinstvene (mada je bilo slučajeva da se ponavlja, npr. skupštine stanara, crkve.. ali mislim da je to sada drugačije). Matični broj pravnog lica / preduzetnika dodeljuje nadležna institucija (APR, Advokatska Komora…). Za preduzetnike matični brojevi počinju na 5 i 6 dok za ostala pravna lica počinju na 0, 1 i 2.

          Nadam se da sam malo pojasnio i da usput nisam ništa pogrešio. :)

  2. Hvala najlepše :) pozdrav!

Leave a Comment

NOTE - You can use these HTML tags and attributes:
<a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>