Created
January 30, 2018 10:57
-
-
Save antonyalkmim/dd2369b358b7ea8cbf423b026233111a to your computer and use it in GitHub Desktop.
Classe para identificar informacoes do boleto a partir do codigo de barras ou linha digitavel
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"id":"246", | |
"name":"Banco ABC Brasil S.A." | |
}, | |
{ | |
"id":"075", | |
"name":"Banco ABN AMRO S.A." | |
}, | |
{ | |
"id":"025", | |
"name":"Banco Alfa S.A." | |
}, | |
{ | |
"id":"641", | |
"name":"Banco Alvorada S.A." | |
}, | |
{ | |
"id":"065", | |
"name":"Banco Andbank (Brasil) S.A." | |
}, | |
{ | |
"id":"024", | |
"name":"Banco BANDEPE S.A." | |
}, | |
{ | |
"id":"740", | |
"name":"Banco Barclays S.A." | |
}, | |
{ | |
"id":"107", | |
"name":"Banco BBM S.A." | |
}, | |
{ | |
"id":"096", | |
"name":"Banco BM&FBOVESPA de Serviços de Liquidação e Custódia S.A" | |
}, | |
{ | |
"id":"318", | |
"name":"Banco BMG S.A." | |
}, | |
{ | |
"id":"752", | |
"name":"Banco BNP Paribas Brasil S.A." | |
}, | |
{ | |
"id":"248", | |
"name":"Banco Boavista Interatlântico S.A." | |
}, | |
{ | |
"id":"218", | |
"name":"Banco Bonsucesso S.A." | |
}, | |
{ | |
"id":"063", | |
"name":"Banco Bradescard S.A." | |
}, | |
{ | |
"id":"036", | |
"name":"Banco Bradesco BBI S.A." | |
}, | |
{ | |
"id":"204", | |
"name":"Banco Bradesco Cartões S.A." | |
}, | |
{ | |
"id":"394", | |
"name":"Banco Bradesco Financiamentos S.A." | |
}, | |
{ | |
"id":"237", | |
"name":"Banco Bradesco S.A." | |
}, | |
{ | |
"id":"208", | |
"name":"Banco BTG Pactual S.A." | |
}, | |
{ | |
"id":"263", | |
"name":"Banco Cacique S.A." | |
}, | |
{ | |
"id":"473", | |
"name":"Banco Caixa Geral - Brasil S.A." | |
}, | |
{ | |
"id":"040", | |
"name":"Banco Cargill S.A." | |
}, | |
{ | |
"id":"739", | |
"name":"Banco Cetelem S.A." | |
}, | |
{ | |
"id":"233", | |
"name":"Banco Cifra S.A." | |
}, | |
{ | |
"id":"745", | |
"name":"Banco Citibank S.A." | |
}, | |
{ | |
"id":"000", | |
"name":"Banco CNH Industrial Capital S.A." | |
}, | |
{ | |
"id":"095", | |
"name":"Banco Confidence de Câmbio S.A." | |
}, | |
{ | |
"id":"756", | |
"name":"Banco Cooperativo do Brasil S.A. - BANCOOB" | |
}, | |
{ | |
"id":"748", | |
"name":"Banco Cooperativo Sicredi S.A." | |
}, | |
{ | |
"id":"222", | |
"name":"Banco Credit Agricole Brasil S.A." | |
}, | |
{ | |
"id":"505", | |
"name":"Banco Credit Suisse (Brasil) S.A." | |
}, | |
{ | |
"id":"003", | |
"name":"Banco da Amazônia S.A." | |
}, | |
{ | |
"id":"083", | |
"name":"Banco da China Brasil S.A." | |
}, | |
{ | |
"id":"707", | |
"name":"Banco Daycoval S.A." | |
}, | |
{ | |
"id":"456", | |
"name":"Banco de Tokyo-Mitsubishi UFJ Brasil S.A." | |
}, | |
{ | |
"id":"001", | |
"name":"Banco do Brasil S.A." | |
}, | |
{ | |
"id":"047", | |
"name":"Banco do Estado de Sergipe S.A." | |
}, | |
{ | |
"id":"037", | |
"name":"Banco do Estado do Pará S.A." | |
}, | |
{ | |
"id":"041", | |
"name":"Banco do Estado do Rio Grande do Sul S.A." | |
}, | |
{ | |
"id":"004", | |
"name":"Banco do Nordeste do Brasil S.A." | |
}, | |
{ | |
"id":"265", | |
"name":"Banco Fator S.A." | |
}, | |
{ | |
"id":"224", | |
"name":"Banco Fibra S.A." | |
}, | |
{ | |
"id":"626", | |
"name":"Banco Ficsa S.A." | |
}, | |
{ | |
"id":"612", | |
"name":"Banco Guanabara S.A." | |
}, | |
{ | |
"id":"012", | |
"name":"Banco INBURSA de Investimentos S.A." | |
}, | |
{ | |
"id":"604", | |
"name":"Banco Industrial do Brasil S.A." | |
}, | |
{ | |
"id":"653", | |
"name":"Banco Indusval S.A." | |
}, | |
{ | |
"id":"249", | |
"name":"Banco Investcred Unibanco S.A." | |
}, | |
{ | |
"id":"184", | |
"name":"Banco Itaú BBA S.A." | |
}, | |
{ | |
"id":"029", | |
"name":"Banco Itaú BMG Consignado S.A." | |
}, | |
{ | |
"id":"479", | |
"name":"Banco ItaúBank S.A" | |
}, | |
{ | |
"id":"376", | |
"name":"Banco J. P. Morgan S.A." | |
}, | |
{ | |
"id":"074", | |
"name":"Banco J. Safra S.A." | |
}, | |
{ | |
"id":"217", | |
"name":"Banco John Deere S.A." | |
}, | |
{ | |
"id":"600", | |
"name":"Banco Luso Brasileiro S.A." | |
}, | |
{ | |
"id":"389", | |
"name":"Banco Mercantil do Brasil S.A." | |
}, | |
{ | |
"id":"370", | |
"name":"Banco Mizuho do Brasil S.A." | |
}, | |
{ | |
"id":"746", | |
"name":"Banco Modal S.A." | |
}, | |
{ | |
"id":"212", | |
"name":"Banco Original S.A." | |
}, | |
{ | |
"id":"623", | |
"name":"Banco PAN S.A." | |
}, | |
{ | |
"id":"611", | |
"name":"Banco Paulista S.A." | |
}, | |
{ | |
"id":"094", | |
"name":"Banco Petra S.A." | |
}, | |
{ | |
"id":"643", | |
"name":"Banco Pine S.A." | |
}, | |
{ | |
"id":"747", | |
"name":"Banco Rabobank International Brasil S.A." | |
}, | |
{ | |
"id":"633", | |
"name":"Banco Rendimento S.A." | |
}, | |
{ | |
"id":"120", | |
"name":"Banco Rodobens S.A." | |
}, | |
{ | |
"id":"422", | |
"name":"Banco Safra S.A." | |
}, | |
{ | |
"id":"033", | |
"name":"Banco Santander (Brasil) S.A." | |
}, | |
{ | |
"id":"366", | |
"name":"Banco Société Générale Brasil S.A." | |
}, | |
{ | |
"id":"464", | |
"name":"Banco Sumitomo Mitsui Brasileiro S.A." | |
}, | |
{ | |
"id":"082", | |
"name":"Banco Topázio S.A." | |
}, | |
{ | |
"id":"634", | |
"name":"Banco Triângulo S.A." | |
}, | |
{ | |
"id":"655", | |
"name":"Banco Votorantim S.A." | |
}, | |
{ | |
"id":"610", | |
"name":"Banco VR S.A." | |
}, | |
{ | |
"id":"119", | |
"name":"Banco Western Union do Brasil S.A." | |
}, | |
{ | |
"id":"021", | |
"name":"BANESTES S.A. Banco do Estado do Espírito Santo" | |
}, | |
{ | |
"id":"719", | |
"name":"Banif-Banco Internacional do Funchal (Brasil)S.A." | |
}, | |
{ | |
"id":"755", | |
"name":"Bank of America Merrill Lynch Banco Múltiplo S.A." | |
}, | |
{ | |
"id":"081", | |
"name":"BBN Banco Brasileiro de Negócios S.A." | |
}, | |
{ | |
"id":"250", | |
"name":"BCV - Banco de Crédito e Varejo S.A." | |
}, | |
{ | |
"id":"017", | |
"name":"BNY Mellon Banco S.A." | |
}, | |
{ | |
"id":"069", | |
"name":"BPN Brasil Banco Múltiplo S.A." | |
}, | |
{ | |
"id":"125", | |
"name":"Brasil Plural S.A. - Banco Múltiplo" | |
}, | |
{ | |
"id":"070", | |
"name":"BRB - Banco de Brasília S.A." | |
}, | |
{ | |
"id":"104", | |
"name":"Caixa Econômica Federal" | |
}, | |
{ | |
"id":"320", | |
"name":"China Construction Bank (Brasil) Banco Múltiplo S.A." | |
}, | |
{ | |
"id":"477", | |
"name":"Citibank N.A." | |
}, | |
{ | |
"id":"487", | |
"name":"Deutsche Bank S.A. - Banco Alemão" | |
}, | |
{ | |
"id":"064", | |
"name":"Goldman Sachs do Brasil Banco Múltiplo S.A." | |
}, | |
{ | |
"id":"078", | |
"name":"Haitong Banco de Investimento do Brasil S.A." | |
}, | |
{ | |
"id":"062", | |
"name":"Hipercard Banco Múltiplo S.A." | |
}, | |
{ | |
"id":"399", | |
"name":"HSBC Bank Brasil S.A. - Banco Múltiplo" | |
}, | |
{ | |
"id":"492", | |
"name":"ING Bank N.V." | |
}, | |
{ | |
"id":"652", | |
"name":"Itaú Unibanco Holding S.A." | |
}, | |
{ | |
"id":"341", | |
"name":"Itaú Unibanco S.A." | |
}, | |
{ | |
"id":"488", | |
"name":"JPMorgan Chase Bank, National Association" | |
}, | |
{ | |
"id":"128", | |
"name":"MSB Bank S.A. Banco de Câmbio" | |
}, | |
{ | |
"id":"254", | |
"name":"Paraná Banco S.A." | |
}, | |
{ | |
"id":"751", | |
"name":"Scotiabank Brasil S.A. Banco Múltiplo" | |
}, | |
{ | |
"id":"118", | |
"name":"Standard Chartered Bank (Brasil) S/A–Bco Invest." | |
}, | |
{ | |
"id":"129", | |
"name":"UBS Brasil Banco de Investimento S.A." | |
}, | |
{ | |
"id" : "077", | |
"name": "Banco Inter" | |
} | |
] |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// Billit.swift | |
// antonyalkmim | |
// | |
// Implementacao da classe boleto para identificar valor, data de vencimento e linha digitavel a partir de um codigo de barras | |
// ou identificar valor e data de vencimento a partir de uma linha digitavel. | |
// Todas as regras implementadas seguem a documentacao da FEBRABRAN (https://cmsportal.febraban.org.br/Arquivos/documentos/PDF/Layout%20-%20C%C3%B3digo%20de%20Barras%20-%20Vers%C3%A3o%205%20-%2001_08_2016.pdf) | |
// | |
// Created by Antony Alkmim on 26/01/18. | |
// | |
import Foundation | |
enum BillitError: Swift.Error { | |
case invalidBarcode | |
} | |
class Billit { | |
/// representacao numerica do codigo de barras | |
var barcode: String? | |
/// Linha digitavel | |
var barcodeLine: String? | |
/// Data de vencimento do boleto | |
let dueDate: Date? | |
/// valor do boleto | |
let value: Double? | |
/// Nome do emissor, banco ou convênio | |
let bankName: String | |
/// Inicializa um Boleto a partir da linha digitavel do boleto | |
/// | |
/// - Parameter barcodeLine: Linha digitável do boleto | |
init(withBarcodeLine barcodeLine: String) { | |
var _barcode = barcodeLine | |
.replacingOccurrences(of: " ", with: "") | |
.replacingOccurrences(of: ".", with: "") | |
.replacingOccurrences(of: "-", with: "") | |
//Boletos de arrecardação se a primeira posição começa com 8 | |
if _barcode[0] == "8" { | |
self.barcodeLine = _barcode | |
// remover digitos verificadores da linha digitavel | |
_barcode.remove(at: barcodeLine.index(for: 11)) | |
_barcode.remove(at: barcodeLine.index(for: 22)) | |
_barcode.remove(at: barcodeLine.index(for: 33)) | |
_barcode.remove(at: barcodeLine.index(for: 44)) | |
self.barcode = _barcode | |
// SEGMENT | |
let segmentId = _barcode[1] | |
bankName = segmentNameFor(segmentId: segmentId) ?? "Convênio Desconhecido" | |
// VALUE | |
value = _barcode[2] == "6" || _barcode[2] == "8" ? Double(_barcode[4...14])! / 100 : nil | |
/// DUE DATE | |
let dateformatter = DateFormatter() | |
dateformatter.locale = Locale(identifier: "pt_BR") | |
dateformatter.dateFormat = "yyyyMMdd" | |
dateformatter.timeZone = TimeZone(identifier: "America/Sao_Paulo") | |
// data parseada para caso campo livre vai de 20...44 ou 24...44 | |
dueDate = dateformatter.date(from: _barcode[19...43][0...7]) ?? dateformatter.date(from: _barcode[23...43][0...7]) | |
} else { //boletos de cobranças | |
//Codigo do banco 0 a 2 | |
let bankId = _barcode[0...2] | |
//Fator de vencimento (posições 5 a 8 do código de barras) | |
let dueFactory = _barcode[33...36] | |
// Valor nominal do título (posições 10 a 19 do código de barras) | |
let valueReaded = _barcode[37...46] | |
self.barcodeLine = _barcode | |
self.barcode = nil | |
self.dueDate = dueDateFor(factory: dueFactory) | |
self.value = Double(valueReaded)! / 100 | |
self.bankName = bankNameFor(bankId: bankId) ?? "Banco Desconhecido" | |
} | |
} | |
/// Inicializa um boleto a partir da representacao numerica do codigo de barras | |
/// | |
/// - Parameter barcode: codigo de barras | |
init(withBarcode barcode: String) { | |
var _barcode = barcode | |
.replacingOccurrences(of: " ", with: "") | |
.replacingOccurrences(of: ".", with: "") | |
.replacingOccurrences(of: "-", with: "") | |
//barcode should contain more than 44 characteres | |
guard _barcode.count >= 44 else { | |
fatalError("Billit barcode should contain 44 characteres or more") | |
} | |
self.barcode = _barcode | |
self.barcodeLine = Billit.linhaDigitavelFrom(_barcode)? | |
.replacingOccurrences(of: " ", with: "") | |
.replacingOccurrences(of: ".", with: "") | |
.replacingOccurrences(of: "-", with: "") | |
//Boletos de arrecardação se a primeira posição começa com 8 | |
if _barcode[0] == "8" { | |
// SEGMENT | |
let segmentId = _barcode[1] | |
bankName = segmentNameFor(segmentId: segmentId) ?? "Convênio Desconhecido" | |
// VALUE | |
value = _barcode[2] == "6" || _barcode[2] == "8" ? Double(_barcode[4...14])! / 100 : nil | |
/// DUE DATE | |
let dateformatter = DateFormatter() | |
dateformatter.locale = Locale(identifier: "pt_BR") | |
dateformatter.dateFormat = "yyyyMMdd" | |
dateformatter.timeZone = TimeZone(identifier: "America/Sao_Paulo") | |
// data parseada para caso campo livre vai de 20...44 ou 24...44 | |
dueDate = dateformatter.date(from: _barcode[19...43][0...7]) ?? dateformatter.date(from: _barcode[23...43][0...7]) | |
} else { //boletos de cobranças | |
//Codigo do banco 0 a 2 | |
let bankId = _barcode[0...2] | |
//Fator de vencimento (posições 5 a 8 do código de barras) | |
let dueFactory = _barcode[5...9] | |
// valor real | |
let valueReaded = _barcode[9...19] | |
self.dueDate = dueDateFor(factory: dueFactory) | |
self.value = Double(valueReaded)! / 100 | |
self.bankName = bankNameFor(bankId: bankId) ?? "Banco Desconhecido" | |
} | |
} | |
/// Converte codigo de barras para linha digitavel | |
private static func linhaDigitavelFrom(_ barcode: String) -> String? { | |
// Remover caracteres não numéricos. | |
let _barcode = barcode | |
.replacingOccurrences(of: " ", with: "") | |
.replacingOccurrences(of: ".", with: "") | |
.replacingOccurrences(of: "-", with: "") | |
guard _barcode.count == 44 else { | |
return nil | |
} | |
/// obter campos co codigo de barras | |
let campo1 = _barcode[0...3] + _barcode[19] + "." + _barcode[20...23] | |
let campo2 = _barcode[24...28] + "." + _barcode[29...33] | |
let campo3 = _barcode[34...38] + "." + _barcode[39...43] | |
let campo4 = _barcode[4] // Digito verificador | |
let campo5 = _barcode[5...18] // Vencimento + Valor | |
guard modulo11Banco(_barcode[0...3] + _barcode[5...43]) == Int(campo4)! else { | |
return nil //'Digito verificador '+campo4+', o correto é '+modulo11_banco( linha.substr(0,4)+linha.substr(5,99) )+'\nO sistema não altera automaticamente o dígito correto na quinta casa!' | |
} | |
/// mask 00000.00000 00000.000000 00000.000000 0 00000000000000 | |
return "\(campo1)\(modulo10(campo1)) \(campo2)\(modulo10(campo2)) \(campo3)\(modulo10(campo3)) \(campo4) \(campo5)" | |
} | |
private static func modulo10(_ num: String) -> Int { | |
let numero = num.replacingOccurrences(of: " ", with: "") | |
.replacingOccurrences(of: ".", with: "") | |
.replacingOccurrences(of: "-", with: "") | |
var soma = 0 | |
var peso = 2 | |
var contador = numero.count - 1 | |
while contador >= 0 { | |
var multiplicacao = Int(numero[contador])! * peso | |
if multiplicacao >= 10 { multiplicacao = 1 + (multiplicacao - 10) } | |
soma = soma + multiplicacao | |
peso = peso == 2 ? 1 : 2 | |
contador = contador - 1 | |
} | |
let digito = 10 - (soma % 10) | |
return digito == 10 ? 0 : digito | |
} | |
private static func modulo11Banco(_ num: String) -> Int { | |
let numero = num.replacingOccurrences(of: " ", with: "") | |
.replacingOccurrences(of: ".", with: "") | |
.replacingOccurrences(of: "-", with: "") | |
var soma = 0 | |
var peso = 2 | |
let base = 9 | |
let contador = numero.count - 1 | |
for i in (0...contador).reversed() { | |
soma = soma + Int(numero[i])! * peso | |
peso = peso < base ? peso + 1 : 2 | |
} | |
var digito = 11 - (soma % 11) | |
digito = digito > 9 ? 0 : digito | |
digito = digito == 0 ? 1 : digito | |
return digito | |
} | |
} | |
extension String { | |
func index(for i: Int) -> String.Index { | |
return self.index(self.startIndex, offsetBy: i) | |
} | |
subscript (bounds: CountableClosedRange<Int>) -> String { | |
let start = index(startIndex, offsetBy: bounds.lowerBound) | |
let end = index(startIndex, offsetBy: bounds.upperBound) | |
return String(self[start...end]) | |
} | |
subscript (bounds: CountableRange<Int>) -> String { | |
let start = index(startIndex, offsetBy: bounds.lowerBound) | |
let end = index(startIndex, offsetBy: bounds.upperBound) | |
return String(self[start..<end]) | |
} | |
subscript (_ nth: Int) -> String { | |
return String(self[index(startIndex, offsetBy: nth)]) | |
} | |
} | |
private func dueDateFor(factory: String) -> Date? { | |
guard factory != "0000" else { | |
return nil | |
} | |
let dateformatter = DateFormatter() | |
dateformatter.locale = Locale(identifier: "pt_BR") | |
dateformatter.dateFormat = "dd/MM/yyyy" | |
dateformatter.timeZone = TimeZone(identifier: "America/Sao_Paulo") | |
// Vencimento e calculado baseado no numero de dias a partir da data base do FEBRABRAN (07/10/1997) | |
let baseFebrabranDate = dateformatter.date(from: "07/10/1997")! | |
let daysFromBaseDate = Int(factory)! | |
return Calendar.current.date(byAdding: .day, value: daysFromBaseDate, to: baseFebrabranDate) | |
} | |
private func readJson(withName filename: String, bundle: Bundle = Bundle.main) -> Data! { | |
let path = bundle.path(forResource: filename, ofType: "json") | |
return (try? Data(contentsOf: URL(fileURLWithPath: path!))) | |
} | |
private func bankNameFor(bankId: String) -> String? { | |
let jsonData = readJson(withName: "banks")! | |
let banksJson = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [[String: String]] | |
let bank = banksJson.first { $0["id"] == bankId } | |
return bank?["name"] | |
} | |
private func segmentNameFor(segmentId: String) -> String? { | |
let jsonData = readJson(withName: "segments")! | |
let segmentsJson = try! JSONSerialization.jsonObject(with: jsonData, options: []) as! [[String: String]] | |
let segment = segmentsJson.first { $0["id"] == segmentId } | |
return segment?["name"] | |
} | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[ | |
{ | |
"id":"1", | |
"name":"Prefeituras" | |
}, | |
{ | |
"id":"2", | |
"name":"Saneamento" | |
}, | |
{ | |
"id":"3", | |
"name":"Energia Elétrica e Gás" | |
}, | |
{ | |
"id":"4", | |
"name":"Telecomunicações" | |
}, | |
{ | |
"id":"5", | |
"name":"Órgãos Governamentais" | |
}, | |
{ | |
"id":"6", | |
"name":"Carnes e Assemelhados ou Outros" | |
}, | |
{ | |
"id":"7", | |
"name":"Multas de trânsito" | |
}, | |
{ | |
"id":"9", | |
"name":"Uso exclusivo do banco" | |
} | |
] |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment