package br.com.concretesolutions.canarinho.formatador; import br.com.concretesolutions.canarinho.DigitoPara; import br.com.concretesolutions.canarinho.validator.ValidadorBoleto; /** * Transforma a linha digitável de um boleto em um código de boleto e vice-versa. Use o metodo {@link #formata(String)} * para transformar a linha digitavel em boleto e {@link #desformata(String)}. * Para verificar se um valor esta em linha digitável ou em boleto, usar os métodos: * <ul> * <li>{@link #estaFormatado(String)}: indicará se está em formata de boleto</li> * <li>{@link #podeSerFormatado(String)}: indicará se é uma linha digitável</li> * </ul> */ public final class FormatadorLinhaDigitavel implements Formatador { private FormatadorLinhaDigitavel() { } static FormatadorLinhaDigitavel getInstance() { return SingletonHolder.INSTANCE; } @Override public String formata(String value) { if (value == null || value.length() != 44) { throw new IllegalArgumentException("Linha digitável deve conter 44 caracteres. " + value); } if (value.startsWith("8")) { final String primeiroBloco = value.substring(0, 11); final String segundoBloco = value.substring(11, 22); final String terceiroBloco = value.substring(22, 33); final String quartoBloco = value.substring(33, 44); // o terceiro dígito é o de valor real que define se será mod 10 ou mod 11 final boolean ehMod10 = value.charAt(2) == '6' || value.charAt(2) == '7'; final DigitoPara mod = ehMod10 ? ValidadorBoleto.MOD_10 : ValidadorBoleto.MOD_11; final String primeiroDigito = mod.calcula(primeiroBloco); final String segundoDigito = mod.calcula(segundoBloco); final String terceiroDigito = mod.calcula(terceiroBloco); final String quartoDigito = mod.calcula(quartoBloco); return primeiroBloco + primeiroDigito + segundoBloco + segundoDigito + terceiroBloco + terceiroDigito + quartoBloco + quartoDigito; } String primeiroBloco = value.substring(0, 4); // 4 String segundoBloco = value.substring(4, 19); // 15 String terceiroBloco = value.substring(19, 24); // 5 String quartoBloco = value.substring(24, 34); // 10 String quintoBloco = value.substring(34, 44); // 10 // 1 - 3 - 4 - 5 - 2 final StringBuilder codigoOrdenado = new StringBuilder(primeiroBloco) .append(terceiroBloco) .append(quartoBloco) .append(quintoBloco) .append(segundoBloco); primeiroBloco = codigoOrdenado.substring(0, 9); segundoBloco = codigoOrdenado.substring(9, 19); terceiroBloco = codigoOrdenado.substring(19, 29); quartoBloco = codigoOrdenado.substring(29); final String primeiroDigito = ValidadorBoleto.MOD_10.calcula(primeiroBloco); final String segundoDigito = ValidadorBoleto.MOD_10.calcula(segundoBloco); final String terceiroDigito = ValidadorBoleto.MOD_10.calcula(terceiroBloco); return primeiroBloco + primeiroDigito + segundoBloco + segundoDigito + terceiroBloco + terceiroDigito + quartoBloco; } @Override public String desformata(String valor) { if (valor == null || "".equals(valor)) { throw new IllegalArgumentException("Valor não pode estar nulo."); } String valorDesformatadao = Padroes.PADRAO_SOMENTE_NUMEROS.matcher(valor).replaceAll(""); if (valorDesformatadao.charAt(0) == '8') { if (valorDesformatadao.length() != 48) { throw new IllegalArgumentException("Valor para boletos que iniciam com 8 deve conter 48 dígitos"); } final StringBuilder builder = new StringBuilder(valorDesformatadao); final String primeiroBloco = builder.substring(0, 11); final String segundoBloco = builder.substring(12, 23); final String terceiroBloco = builder.substring(24, 35); final String quartoBloco = builder.substring(36, 47); return "" + primeiroBloco + segundoBloco + terceiroBloco + quartoBloco; } if (valorDesformatadao.length() != 47) { throw new IllegalArgumentException("Valor para boletos deve conter 47 digitos"); } String primeiroBloco = valorDesformatadao.substring(0, 9); String segundoBloco = valorDesformatadao.substring(10, 20); String terceiroBloco = valorDesformatadao.substring(21, 31); String quartoBloco = valorDesformatadao.substring(32, valorDesformatadao.length()); final StringBuilder boletoOrdenado = new StringBuilder(primeiroBloco) .append(segundoBloco) .append(terceiroBloco) .append(quartoBloco); // 1 - 3 - 4 - 5 - 2 primeiroBloco = boletoOrdenado.substring(0, 4); // 4 segundoBloco = boletoOrdenado.substring(29, 44); // 15 terceiroBloco = boletoOrdenado.substring(4, 9); // 5 quartoBloco = boletoOrdenado.substring(9, 19); // 10 final String quintoBloco = boletoOrdenado.substring(19, 29); // 10 return "" + primeiroBloco + segundoBloco + terceiroBloco + quartoBloco + quintoBloco; } @Override public boolean estaFormatado(String value) { return Formatador.BOLETO.estaFormatado(value); } @Override public boolean podeSerFormatado(String value) { final String sanitizado = Padroes.PADRAO_SOMENTE_NUMEROS.matcher(value).replaceAll(""); return sanitizado.length() == 44; } private static class SingletonHolder { private static final FormatadorLinhaDigitavel INSTANCE = new FormatadorLinhaDigitavel(); } }