Sosiaaliturvatunnuksen tarkistus Angular-direktiivillä

Jep, tuli tarpeeseen ihmetellä Angularin direktiivejä ja validointia – miten sosiaaliturvatunnuksen oikeellisuus validoidaan? Tähän ei löytynyt pikaisella haulla valmista ratkaisua joten ei muuta kuin tekemään oma.

Suomalaista sosiaaliturvatunnusta kun ihmetellään, niin osan tarkistuksista voi hoitaa ihan olemassaolevilla direktiiveillä. Esim. pituus tasan 11 merkkiä, aina. Tunnuksen muodon osalta voi olettaa siinä olevan numeroita ensin kuusi, sitten välimerkki jossa on muuutamia mahdollisuuksia, sitten kolme numeroa, ja tarkistuskoodi joka voi olla numero tai kirjain tietystä valikoimasta. Tämä hoituu komeasti esim. Angularin regex-patternilla.

Mutta syy miksi kirjoitan tätä blogia itselleni muistiin on nimenomaan tuon viimeisen merkin tarkistussumman laskeminen, ja oman custom validation direktiivin teko. Se menee nimittäin näin:

(function() {
  angular.module('app').directive('validSsn', validSSN);

  validSSN.$inject = ['$log'];

  function validSSN($log) {
    var checksumChars = 'abcdefhjklmnprstuvwxy';

    var validateSSN = function(value) {
      if (value === undefined || value.length != 11) {
        return false;
      }
      var datePart = value.substr(0, 6);
      var individualNumber = value.substr(7, 3);
      var checkSumCharacter = value.substr(10).toLowerCase();
      var dividedValueModulo = parseInt(
          String(datePart) + String(individualNumber)) % 31;
      var expected;
      if (dividedValueModulo < 10) {
        expected = String(dividedValueModulo);
      } else {
        expected = checksumChars.charAt(dividedValueModulo - 10);
      }
      if (checkSumCharacter === expected) {
        return true;
      } else {
        $log.debug('Expected checksum ', expected,
          ', got checksum ', checkSumCharacter);
        return false;
      }
    };

    return {
      restrict: 'A',
      require: 'ngModel',
      link: function(scope, elem, attr, ctrl) {
        ctrl.$parsers.unshift(function(value) {
          var valid = validateSSN(value);
          ctrl.$setValidity('valid-ssn', valid);
          return value;
        });

        ctrl.$formatters.unshift(function(value) {
          var valid = validateSSN(value);
          ctrl.$setValidity('valid-ssn', valid);
          return value;
        });

      }
    };
  }
}());

No niin, tuossa on vielä paljonkin siistittävää ja optimoitavaa, mutta jätetään se itsekunkin omaksi harjoitukseksi. Idea käy silti ilmi. Katsotaan ensin että arvo on olemassa ja oikean mittainen – ellei, se automaattisti ei läpäise validointia. Jos mitta on oikea, otetaan kaikki data-osan numerot, 9 kappaletta, merkkijonona, ja jaetaan alkuluvulla 31. Jakojäännös kiinnostaa – jos se on alle 10 se on suoraan tarkistuskoodi, jos se on 10 tai yli, verrataan kirjaintaulukkoon josta on muutama kirjain selvyyden vuoksi poistettu.

Sitä voi testata esim. näin:

it('should pass validation with valid ssn', function() {

  var element =
        $compile(
          '<form name="form">' +
            '<input valid-ssn name="ssn" ng-model="value" />' +
          '</form>')($rootScope);
  var form = $rootScope.form;

  $rootScope.value = '140785-940X';
  $rootScope.$digest();
  expect(form.ssn.$valid).toBeTruthy();

  $rootScope.value = '140785-940x';
  $rootScope.$digest();
  expect(form.ssn.$valid).toBeTruthy();

  $rootScope.value = '140785-9143';
  $rootScope.$digest();
  expect(form.ssn.$valid).toBeTruthy();

});

Tällaista tällä kertaa. Jos hommaa haluaisi vielä kehittää. voi toki tarkistaa että päivämäärä on oikea, sukupuoli vastaa muualla annettua tietoa, if any, jne.

Advertisements

Vastaa

Täytä tietosi alle tai klikkaa kuvaketta kirjautuaksesi sisään:

WordPress.com-logo

Olet kommentoimassa WordPress.com -tilin nimissä. Log Out / Muuta )

Twitter-kuva

Olet kommentoimassa Twitter -tilin nimissä. Log Out / Muuta )

Facebook-kuva

Olet kommentoimassa Facebook -tilin nimissä. Log Out / Muuta )

Google+ photo

Olet kommentoimassa Google+ -tilin nimissä. Log Out / Muuta )

Muodostetaan yhteyttä palveluun %s