package br.com.caelum.stella.validation; import java.util.ArrayList; import java.util.List; import java.util.regex.Pattern; import br.com.caelum.stella.DigitoGenerator; import br.com.caelum.stella.DigitoPara; import br.com.caelum.stella.MessageProducer; import br.com.caelum.stella.SimpleMessageProducer; import br.com.caelum.stella.ValidationMessage; import br.com.caelum.stella.format.NITFormatter; import br.com.caelum.stella.validation.error.NITError; /** * <p> * Validador do Número de Identificação do Trabalhador. Este documento contém 11 * (onze) caracteres numéricos, no formato ddd.ddddd.dd-d. * </p> * <p> * O NIT corresponde ao número do <b>PIS/PASEP/CI</b> sendo que, no caso de * Contribuinte Individual (CI), pode ser utilizado o número de inscrição no * Sistema Único de Saúde (SUS) ou na Previdência Social. * </p> * * @author Leonardo Bessa */ public class NITValidator implements Validator<String> { public static final Pattern FORMATED = Pattern.compile("(\\d{3})[.](\\d{5})[.](\\d{2})-(\\d{1})"); public static final Pattern UNFORMATED = Pattern.compile("(\\d{3})(\\d{5})(\\d{2})(\\d{1})"); private boolean isFormatted = false; private MessageProducer messageProducer; /** * Este considera, por padrão, que as cadeias não estão formatadas e utiliza um * {@linkplain SimpleMessageProducer} para geração de mensagens. */ public NITValidator() { this.messageProducer = new SimpleMessageProducer(); } /** * O validador utiliza um {@linkplain SimpleMessageProducer} para geração de * mensagens. * @param isFormatted * considera cadeia no formato de NIT: "ddd.ddddd.dd-d" onde "d" * é um dígito decimal. */ public NITValidator(boolean isFormatted) { this.messageProducer = new SimpleMessageProducer(); this.isFormatted = isFormatted; } /** * <p> * Construtor do Validador de NIT. * </p> * * @param messageProducer * produtor de mensagem de erro. * @param isFormatted * considera cadeia no formato de NIT: "ddd.ddddd.dd-d" onde "d" * é um dígito decimal. */ public NITValidator(MessageProducer messageProducer, boolean isFormatted) { this.messageProducer = messageProducer; this.isFormatted = isFormatted; } private List<ValidationMessage> getInvalidValues(String nit) { List<ValidationMessage> errors = new ArrayList<ValidationMessage>(); if (nit != null) { if(isFormatted && !FORMATED.matcher(nit).matches()){ errors.add(messageProducer.getMessage(NITError.INVALID_FORMAT)); } String unformatedNIT = null; try{ unformatedNIT = new NITFormatter().unformat(nit); }catch(IllegalArgumentException e){ errors.add(messageProducer.getMessage(NITError.INVALID_DIGITS)); return errors; } if(unformatedNIT.length() != 11 || !unformatedNIT.matches("[0-9]*")){ errors.add(messageProducer.getMessage(NITError.INVALID_DIGITS)); } String nitSemDigito = unformatedNIT.substring(0, unformatedNIT.length() - 1); String digitos = unformatedNIT.substring(unformatedNIT.length() - 1); String digitosCalculados = calculaDigitos(nitSemDigito); if(!digitos.equals(digitosCalculados)){ errors.add(messageProducer.getMessage(NITError.INVALID_CHECK_DIGITS)); } } return errors; } private String calculaDigitos(String nitSemDigito) { return new DigitoPara(nitSemDigito).complementarAoModulo().trocandoPorSeEncontrar("0",10,11).mod(11).calcula(); } public boolean isEligible(String value) { boolean result; if (isFormatted) { result = FORMATED.matcher(value).matches(); } else { result = UNFORMATED.matcher(value).matches(); } return result; } public void assertValid(String nit) { List<ValidationMessage> errors = getInvalidValues(nit); if (!errors.isEmpty()) { throw new InvalidStateException(errors); } } public List<ValidationMessage> invalidMessagesFor(String nit) { return getInvalidValues(nit); } @Override public String generateRandomValid() { final String nitSemDigito = new DigitoGenerator().generate(10); final String nitComDigito = nitSemDigito + calculaDigitos(nitSemDigito); if (isFormatted) { return new NITFormatter().format(nitComDigito); } return nitComDigito; } }