From 7d4e469c54ccd40844261c67cc901e1af69688dd Mon Sep 17 00:00:00 2001 From: defendi Date: Thu, 16 Jan 2020 12:34:46 -0300 Subject: [PATCH 1/6] =?UTF-8?q?Impress=C3=A3o=20do=20campo=20Sacador?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .project | 17 ++++++++++++ .pydevproject | 8 ++++++ .settings/org.eclipse.core.resources.prefs | 3 +++ pyboleto/pdf.py | 30 +++++++++++++++++++--- 4 files changed, 55 insertions(+), 3 deletions(-) create mode 100644 .project create mode 100644 .pydevproject create mode 100644 .settings/org.eclipse.core.resources.prefs diff --git a/.project b/.project new file mode 100644 index 0000000..0ec7c7d --- /dev/null +++ b/.project @@ -0,0 +1,17 @@ + + + boleto + + + + + + org.python.pydev.PyDevBuilder + + + + + + org.python.pydev.pythonNature + + diff --git a/.pydevproject b/.pydevproject new file mode 100644 index 0000000..ad74947 --- /dev/null +++ b/.pydevproject @@ -0,0 +1,8 @@ + + + +/${PROJECT_DIR_NAME} + +python interpreter +Default + diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs new file mode 100644 index 0000000..fc0a1c9 --- /dev/null +++ b/.settings/org.eclipse.core.resources.prefs @@ -0,0 +1,3 @@ +eclipse.preferences.version=1 +encoding//pyboleto/pdf.py=utf-8 +encoding/setup.py=utf-8 diff --git a/pyboleto/pdf.py b/pyboleto/pdf.py index c6fdc37..7e2b353 100644 --- a/pyboleto/pdf.py +++ b/pyboleto/pdf.py @@ -253,6 +253,12 @@ def _drawReciboSacado(self, boleto_dados, x, y): self.pdf_canvas.setFont('Helvetica', 6) self.delta_title = self.height_line - (6 + 1) + self.pdf_canvas.drawString( + 0, + self.height_line, + 'Sacador / Avalista' + ) + self.pdf_canvas.drawRightString( self.width, self.height_line, @@ -387,6 +393,14 @@ def _drawReciboSacado(self, boleto_dados, x, y): valor_documento ) + if boleto_dados.sacador_documento and boleto_dados.sacador_nome: + self.pdf_canvas.setFont('Helvetica', 6) + self.pdf_canvas.drawString( + 0, + self.height_line - 8, + boleto_dados.sacador_documento + ' - ' + boleto_dados.sacador_nome + ) + self.pdf_canvas.setFont('Courier', 9) demonstrativo = boleto_dados.demonstrativo[0:25] for i in range(len(demonstrativo)): @@ -440,7 +454,7 @@ def _drawReciboCaixa(self, boleto_dados, x, y): y = 1.5 * self.height_line self.pdf_canvas.drawRightString( self.width, - (1.5 * self.height_line) + self.delta_title - 1, + y + self.delta_title - 1, 'Autenticação Mecânica / Ficha de Compensação' ) @@ -452,9 +466,19 @@ def _drawReciboCaixa(self, boleto_dados, x, y): self.width - (45 * mm) + self.space, y + self.space, 'Código de baixa' ) + self.pdf_canvas.drawString(0, y + self.space, 'Sacador / Avalista') + if boleto_dados.sacador_documento and boleto_dados.sacador_nome: + self.pdf_canvas.setFont('Helvetica-Bold', self.font_size_title-0.5) + self.pdf_canvas.drawString( + (20 * mm), + y + self.space, + boleto_dados.sacador_documento + ' / ' + boleto_dados.sacador_nome + ) - y += self.height_line + self.pdf_canvas.setFont('Helvetica', self.font_size_title) + + y += self.height_line + 7 self.pdf_canvas.drawString(0, y + self.delta_title, 'Pagador') sacado = boleto_dados.sacado @@ -817,7 +841,7 @@ def drawBoleto(self, boleto_dados): y = 10 * mm # margem inferior self._drawHorizontalCorteLine(x, y, self.width) - y += 4 * mm # distancia entre linha de corte e barcode + y += 3 * mm # distancia entre linha de corte e barcode d = self._drawReciboCaixa(boleto_dados, x, y) y += d[1] + (12 * mm) # distancia entre Recibo caixa e linha de corte From 4096a316e2609b1d9030146e19ec1999d997d423 Mon Sep 17 00:00:00 2001 From: defendi Date: Thu, 16 Jan 2020 17:58:59 -0300 Subject: [PATCH 2/6] ajuste tamanho fonte sacador --- pyboleto/pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyboleto/pdf.py b/pyboleto/pdf.py index 7e2b353..9a06f21 100644 --- a/pyboleto/pdf.py +++ b/pyboleto/pdf.py @@ -469,7 +469,7 @@ def _drawReciboCaixa(self, boleto_dados, x, y): self.pdf_canvas.drawString(0, y + self.space, 'Sacador / Avalista') if boleto_dados.sacador_documento and boleto_dados.sacador_nome: - self.pdf_canvas.setFont('Helvetica-Bold', self.font_size_title-0.5) + self.pdf_canvas.setFont('Helvetica-Bold', self.font_size_title-0.3) self.pdf_canvas.drawString( (20 * mm), y + self.space, From c3c6eafa90ea9c5575affbb7c0c9b225db59e0f0 Mon Sep 17 00:00:00 2001 From: Defendi Date: Thu, 20 May 2021 18:06:27 -0300 Subject: [PATCH 3/6] boleto bs2 --- .gitignore | 1 + .settings/org.eclipse.core.resources.prefs | 5 ++ pyboleto/bank/bs2.py | 57 +++++++++++++++++++++ pyboleto/media/logo_bs2.png | Bin 0 -> 6998 bytes tests/test_banco_bs2.py | 54 +++++++++++++++++++ 5 files changed, 117 insertions(+) create mode 100644 pyboleto/bank/bs2.py create mode 100644 pyboleto/media/logo_bs2.png create mode 100644 tests/test_banco_bs2.py diff --git a/.gitignore b/.gitignore index 93c111b..b477ac8 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,4 @@ venv .cache .pytest_cache +.settings \ No newline at end of file diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index fc0a1c9..9e4566c 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,3 +1,8 @@ eclipse.preferences.version=1 +encoding//pyboleto/bank/bs2.py=utf-8 +encoding//pyboleto/bank/itau.py=utf-8 +encoding//pyboleto/bank/sicredi.py=utf-8 +encoding//pyboleto/data.py=utf-8 encoding//pyboleto/pdf.py=utf-8 +encoding//tests/test_banco_bs2.py=utf-8 encoding/setup.py=utf-8 diff --git a/pyboleto/bank/bs2.py b/pyboleto/bank/bs2.py new file mode 100644 index 0000000..a6add7c --- /dev/null +++ b/pyboleto/bank/bs2.py @@ -0,0 +1,57 @@ +# -*- coding: utf-8 -*- +from pyboleto.data import BoletoData, CustomProperty + + +class BoletoBs2(BoletoData): + '''Implementa Boleto bs2 + + Gera Dados necessários para criação de boleto para o banco Bs2 + + ''' + + # Nosso numero (sem dv) com 8 digitos + nosso_numero = CustomProperty('nosso_numero', 8) + # Conta (sem dv) com 5 digitos + conta_cedente = CustomProperty('conta_cedente', 5) + # Agência (sem dv) com 4 digitos + agencia_cedente = CustomProperty('agencia_cedente', 4) + carteira = 'Cbr Simples' + + def __init__(self): + super(BoletoBs2, self).__init__() + + self.codigo_banco = "218" + self.logo_image = "logo_bs2.jpg" + self.especie_documento = 'Outro' + self.local_pagamento = 'Pagável em qualquer banco.' + + @property + def dv_nosso_numero(self): + composto = "9%s" % str(self.nosso_numero).zfill(10) + return self.modulo11(composto) + + @property + def dv_agencia_conta_cedente(self): + agencia_conta = "%s%s" % (self.agencia_cedente, self.conta_cedente) + return self.modulo10(agencia_conta) + + @property + def agencia_conta_cedente(self): + return "%s/%s-%s" % (self.agencia_cedente, self.conta_cedente, + self.conta_cedente_dv) + + def format_nosso_numero(self): + return "%3s/%8s-%1s" % (self.carteira, self.nosso_numero, + self.dv_nosso_numero) + + @property + def campo_livre(self): + content = "%3s%8s%1s%4s%5s%1s%3s" % (self.carteira, + self.nosso_numero, + self.dv_nosso_numero, + self.agencia_cedente, + self.conta_cedente, + self.conta_cedente_dv, + '000' + ) + return content diff --git a/pyboleto/media/logo_bs2.png b/pyboleto/media/logo_bs2.png new file mode 100644 index 0000000000000000000000000000000000000000..2a44617395109bd0aac477787ec2c913c3ccad17 GIT binary patch literal 6998 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 literal 0 HcmV?d00001 diff --git a/tests/test_banco_bs2.py b/tests/test_banco_bs2.py new file mode 100644 index 0000000..cf69177 --- /dev/null +++ b/tests/test_banco_bs2.py @@ -0,0 +1,54 @@ +# -*- coding: utf-8 -*- +import unittest +import datetime + +from pyboleto.bank.itau import BoletoItau + +from .testutils import BoletoTestCase + + +class TestBancoItau(BoletoTestCase): + def setUp(self): + self.dados = [] + for i in range(3): + d = BoletoItau() + d.carteira = '109' + d.agencia_cedente = '0293' + d.conta_cedente = '01328' + d.conta_cedente_dv = '1' + d.data_vencimento = datetime.date(2009, 10, 19) + d.data_documento = datetime.date(2009, 10, 19) + d.data_processamento = datetime.date(2009, 10, 19) + d.valor_documento = 29.80 + d.nosso_numero = str(157 + i) + d.numero_documento = str(456 + i) + self.dados.append(d) + + def test_linha_digitavel(self): + self.assertEqual( + self.dados[0].linha_digitavel, + '34191.09008 00015.710296 30132.810000 4 43950000002980' + ) + + def test_codigo_de_barras(self): + self.assertEqual( + self.dados[0].barcode, + '34194439500000029801090000015710293013281000' + ) + + def test_agencia(self): + self.assertEqual(self.dados[0].agencia_cedente, '0293') + + def test_conta(self): + self.assertEqual(self.dados[0].conta_cedente, '01328') + + def test_dv_nosso_numero(self): + self.assertEqual(self.dados[0].dv_nosso_numero, 1) + + def test_dv_agencia_conta_cedente(self): + self.assertEqual(self.dados[0].dv_agencia_conta_cedente, 0) + +suite = unittest.TestLoader().loadTestsFromTestCase(TestBancoItau) + +if __name__ == '__main__': + unittest.main() From 7770033ab8db7ea0ce9f4164c418b2d474be7e73 Mon Sep 17 00:00:00 2001 From: Defendi Date: Tue, 25 May 2021 11:56:31 -0300 Subject: [PATCH 4/6] =?UTF-8?q?Impress=C3=A3o=20autom=C3=A1tica=20da=20tx?= =?UTF-8?q?=20de=20juros=20e=20multa?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .settings/org.eclipse.core.resources.prefs | 5 + pyboleto/bank/__init__.py | 7 +- pyboleto/bank/bs2.py | 34 ++--- pyboleto/data.py | 9 +- pyboleto/media/logo_bs2.png | Bin 6998 -> 9717 bytes pyboleto/pdf.py | 20 +++ tests/test_banco_bs2.py | 152 +++++++++++++++------ tests/xml/BoletoBs2-expected.xml | 0 8 files changed, 164 insertions(+), 63 deletions(-) create mode 100644 tests/xml/BoletoBs2-expected.xml diff --git a/.settings/org.eclipse.core.resources.prefs b/.settings/org.eclipse.core.resources.prefs index 9e4566c..9480eef 100644 --- a/.settings/org.eclipse.core.resources.prefs +++ b/.settings/org.eclipse.core.resources.prefs @@ -1,8 +1,13 @@ eclipse.preferences.version=1 +encoding//build/lib/pyboleto/bank/bs2.py=utf-8 +encoding//pyboleto/bank/__init__.py=utf-8 +encoding//pyboleto/bank/bancodobrasil.py=utf-8 +encoding//pyboleto/bank/banrisul.py=utf-8 encoding//pyboleto/bank/bs2.py=utf-8 encoding//pyboleto/bank/itau.py=utf-8 encoding//pyboleto/bank/sicredi.py=utf-8 encoding//pyboleto/data.py=utf-8 encoding//pyboleto/pdf.py=utf-8 encoding//tests/test_banco_bs2.py=utf-8 +encoding//tests/testutils.py=utf-8 encoding/setup.py=utf-8 diff --git a/pyboleto/bank/__init__.py b/pyboleto/bank/__init__.py index 48dc5e1..66c18e1 100644 --- a/pyboleto/bank/__init__.py +++ b/pyboleto/bank/__init__.py @@ -2,13 +2,14 @@ from ..data import BoletoException BANCOS_IMPLEMENTADOS = { '001': 'bancodobrasil.BoletoBB', + '033': 'santander.BoletoSantander', '041': 'banrisul.BoletoBanrisul', - '237': 'bradesco.BoletoBradesco', '104': 'caixa.BoletoCaixa', - '399': 'hsbc.BoletoHsbc', + '218': 'bs2.BoletoBs2', + '237': 'bradesco.BoletoBradesco', '341': 'itau.BoletoItau', '356': 'real.BoletoReal', - '033': 'santander.BoletoSantander', + '399': 'hsbc.BoletoHsbc', '748': 'sicredi.BoletoSicredi', '756': 'sicoob.BoletoSicoob', '0851': 'cecred.BoletoCecred', diff --git a/pyboleto/bank/bs2.py b/pyboleto/bank/bs2.py index a6add7c..4e9aa10 100644 --- a/pyboleto/bank/bs2.py +++ b/pyboleto/bank/bs2.py @@ -1,4 +1,6 @@ # -*- coding: utf-8 -*- + +import datetime from pyboleto.data import BoletoData, CustomProperty @@ -10,30 +12,32 @@ class BoletoBs2(BoletoData): ''' # Nosso numero (sem dv) com 8 digitos - nosso_numero = CustomProperty('nosso_numero', 8) + nosso_numero = "9%s" % CustomProperty('nosso_numero', 9) # Conta (sem dv) com 5 digitos conta_cedente = CustomProperty('conta_cedente', 5) # Agência (sem dv) com 4 digitos agencia_cedente = CustomProperty('agencia_cedente', 4) - carteira = 'Cbr Simples' + + carteira = 21 + + data_limite = False def __init__(self): super(BoletoBs2, self).__init__() self.codigo_banco = "218" - self.logo_image = "logo_bs2.jpg" + self.logo_image = "logo_bs2.png" self.especie_documento = 'Outro' - self.local_pagamento = 'Pagável em qualquer banco.' + self.local_pagamento = 'Pagável em qualquer banco até a data limite de %s' @property def dv_nosso_numero(self): - composto = "9%s" % str(self.nosso_numero).zfill(10) - return self.modulo11(composto) + return self.modulo11("9"+self.nosso_numero.zfill(9)) @property def dv_agencia_conta_cedente(self): agencia_conta = "%s%s" % (self.agencia_cedente, self.conta_cedente) - return self.modulo10(agencia_conta) + return self.modulo11(agencia_conta) @property def agencia_conta_cedente(self): @@ -41,17 +45,13 @@ def agencia_conta_cedente(self): self.conta_cedente_dv) def format_nosso_numero(self): - return "%3s/%8s-%1s" % (self.carteira, self.nosso_numero, - self.dv_nosso_numero) + return "%9s%1s" % ("9"+self.nosso_numero.zfill(9),self.dv_nosso_numero) @property def campo_livre(self): - content = "%3s%8s%1s%4s%5s%1s%3s" % (self.carteira, - self.nosso_numero, - self.dv_nosso_numero, - self.agencia_cedente, - self.conta_cedente, - self.conta_cedente_dv, - '000' - ) + content = "%3s%9s%1s%10s%1s8" % (self.agencia_cedente.zfill(4)[-3:], + self.conta_cedente.zfill(9), + self.conta_cedente_dv, + '9'+self.nosso_numero.zfill(9), + self.dv_nosso_numero) return content diff --git a/pyboleto/data.py b/pyboleto/data.py index 1b1b0bd..40c1739 100644 --- a/pyboleto/data.py +++ b/pyboleto/data.py @@ -100,6 +100,7 @@ class BoletoData(object): :param cedente_documento: CPF ou CNPJ do Cedente. :param conta_cedente: Conta do Cedente sem o dígito verificador. :param data_documento: + :param data_limite: :type data_documento: `datetime.date` :param data_processamento: :type data_processamento: `datetime.date` @@ -129,6 +130,7 @@ class BoletoData(object): def __init__(self, **kwargs): # otherwise the printed value might diffent from the value in # the barcode. + self.data_limite = kwargs.pop('data_limite', "") self.aceite = kwargs.pop('aceite', "N") self.agencia_cedente = kwargs.pop('agencia_cedente', "") self.carteira = kwargs.pop('carteira', "") @@ -143,13 +145,11 @@ def __init__(self, **kwargs): self.conta_cedente = kwargs.pop('conta_cedente', "") self.conta_cedente_dv = kwargs.pop('conta_cedente_dv', "") self.data_documento = kwargs.pop('data_documento', "") - self.data_processamento = kwargs.pop('data_processamento', - datetime.date.today()) + self.data_processamento = kwargs.pop('data_processamento',datetime.date.today()) self.data_vencimento = kwargs.pop('data_vencimento', "") self.especie = kwargs.pop('especie', "R$") self.especie_documento = kwargs.pop('especie_documento', "") - self.local_pagamento = kwargs.pop( - 'local_pagamento', "Pagável em qualquer banco até o vencimento") + self.local_pagamento = kwargs.pop('local_pagamento', "Pagável em qualquer banco até o vencimento") self.logo_image = kwargs.pop('logo_image', "") self.moeda = kwargs.pop('moeda', "9") self.numero_documento = kwargs.pop('numero_do_documento', "") @@ -161,6 +161,7 @@ def __init__(self, **kwargs): self.sacado_endereco = kwargs.pop('sacado_endereco', "") self.sacado_bairro = kwargs.pop('sacado_bairro', "") self.sacado_cep = kwargs.pop('sacado_cep', "") + self.data_limite = kwargs.pop('data_limite', "") if kwargs: raise TypeError("Paramêtro(s) desconhecido: %r" % (kwargs, )) self._cedente_endereco = None diff --git a/pyboleto/media/logo_bs2.png b/pyboleto/media/logo_bs2.png index 2a44617395109bd0aac477787ec2c913c3ccad17..67039578363ddbfd91abb0f28c0bed9543299486 100644 GIT binary patch delta 9320 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 A+yDRo diff --git a/pyboleto/pdf.py b/pyboleto/pdf.py index 9a06f21..7711e22 100644 --- a/pyboleto/pdf.py +++ b/pyboleto/pdf.py @@ -550,6 +550,26 @@ def _drawReciboCaixa(self, boleto_dados, x, y): y - (i * self.delta_font), instrucoes[i] ) + + ln = 6 + if hasattr(boleto_dados, 'tx_multa'): + mt_txt = "Multa para pagamento após o vencimento: {:.2f}%.".format(boleto_dados.tx_multa) + self.pdf_canvas.drawString( + 2 * self.space, + y - (ln * self.delta_font), + mt_txt + ) + ln += 1 + + if hasattr(boleto_dados, 'tx_juros'): + jr_txt = "Juros para pagamento após o vencimento: {:.2f}% ao mês.".format(boleto_dados.tx_juros) + self.pdf_canvas.drawString( + 2 * self.space, + y - (ln * self.delta_font), + jr_txt + ) + + self.pdf_canvas.setFont('Helvetica', self.font_size_title) # Linha horizontal com primeiro campo Uso do Banco diff --git a/tests/test_banco_bs2.py b/tests/test_banco_bs2.py index cf69177..81b5a73 100644 --- a/tests/test_banco_bs2.py +++ b/tests/test_banco_bs2.py @@ -1,54 +1,128 @@ # -*- coding: utf-8 -*- import unittest import datetime +import difflib +import fnmatch +import os +import re +import subprocess +import tempfile +from xml.etree.ElementTree import fromstring, tostring -from pyboleto.bank.itau import BoletoItau +from pyboleto.bank.bs2 import BoletoBs2 +import pyboleto +from pyboleto.pdf import BoletoPDF +from pyboleto.html import BoletoHTML -from .testutils import BoletoTestCase +def indent(elem, level=0): + i = "\n" + level * " " + if len(elem): + if not elem.text or not elem.text.strip(): + elem.text = i + " " + if not elem.tail or not elem.tail.strip(): + elem.tail = i + for elem in elem: + indent(elem, level + 1) + if not elem.tail or not elem.tail.strip(): + elem.tail = i + else: + if level and (not elem.tail or not elem.tail.strip()): + elem.tail = i -class TestBancoItau(BoletoTestCase): - def setUp(self): - self.dados = [] - for i in range(3): - d = BoletoItau() - d.carteira = '109' - d.agencia_cedente = '0293' - d.conta_cedente = '01328' - d.conta_cedente_dv = '1' - d.data_vencimento = datetime.date(2009, 10, 19) - d.data_documento = datetime.date(2009, 10, 19) - d.data_processamento = datetime.date(2009, 10, 19) - d.valor_documento = 29.80 - d.nosso_numero = str(157 + i) - d.numero_documento = str(456 + i) - self.dados.append(d) +def pdftoxml(filename, output): + p = subprocess.Popen(['pdftohtml', + '-stdout', + '-xml', + '-noframes', + '-i', + '-q', + filename], + stdout=subprocess.PIPE) + stdout, stderr = p.communicate() + if stderr: + raise SystemExit("Error while runnig pdftohtml: %s" % (stderr, )) - def test_linha_digitavel(self): - self.assertEqual( - self.dados[0].linha_digitavel, - '34191.09008 00015.710296 30132.810000 4 43950000002980' - ) + root = fromstring(stdout) + indent(root) + with open(output, 'wb') as f: + f.write(tostring(root)) - def test_codigo_de_barras(self): - self.assertEqual( - self.dados[0].barcode, - '34194439500000029801090000015710293013281000' - ) +def _diff(orig, new, short, verbose): + lines = difflib.unified_diff(orig, new) + if not lines: + return '' - def test_agencia(self): - self.assertEqual(self.dados[0].agencia_cedente, '0293') + return ''.join('%s: %s' % (short, line) for line in lines) - def test_conta(self): - self.assertEqual(self.dados[0].conta_cedente, '01328') +def diff_files(orig, new, verbose=False): + with open(orig) as f_orig: + with open(new) as f_new: + return _diff(f_orig.readlines(), + f_new.readlines(), + short=os.path.basename(orig), + verbose=verbose) - def test_dv_nosso_numero(self): - self.assertEqual(self.dados[0].dv_nosso_numero, 1) +def _get_expected(bank, generated, f_type='xml'): + fname = os.path.join(os.path.dirname(pyboleto.__file__),"..", "tests", f_type, bank + '-expected.' + f_type) + if not os.path.exists(fname): + with open(fname, 'wb') as f: + with open(generated) as g: + f.write(g.read()) + return fname - def test_dv_agencia_conta_cedente(self): - self.assertEqual(self.dados[0].dv_agencia_conta_cedente, 0) +def diff_pdf_htmls(original_filename, filename): + # REPLACE all generated dates with %%DATE%% + for fname in [original_filename, filename]: + with open(fname) as f: + data = f.read() + data = re.sub(r'name="date" content="(.*)"', + r'name="date" content="%%DATE%%"', data) + data = re.sub(r']+>', r'', data) + with open(fname, 'w') as f: + f.write(data) -suite = unittest.TestLoader().loadTestsFromTestCase(TestBancoItau) + return diff_files(original_filename, filename) -if __name__ == '__main__': - unittest.main() +dados = [] +for i in range(3): + d = BoletoBs2() + d.carteira = '21' + d.agencia_cedente = '001' + d.conta_cedente = '892700' + d.conta_cedente_dv = '6' + d.cedente = "M&D Com. E Man. DE Equip. para Inform. Ltda" + d.cedente_cidade = "Fazenda Rio Grande" + d.cedente_uf = "PR" + d.cedente_logradouro = "Rua Aruba" + d.cedente_bairro = "96" + d.cedente_cep = "88888-888" + d.cedente_documento = "123" + d.data_vencimento = datetime.date(2021, 6, 30) + d.data_documento = datetime.date(2021, 5, 25) + d.data_processamento = datetime.date(2021, 5, 20) + #d.self.data_limite = datetime.date(2009, 11, 19) + d.valor_documento = 123.45 + d.nosso_numero = str(2399) + d.numero_documento = str(456) + d.sacador_documento = "" + d.sacador_nome = "" + d.instrucoes = ['Após o vencimento cobrar R$ 1,00 multa e ', 'R$ 0,25 ao dia juros por atraso'] + dados.append(d) + +dados = dados[0] +bank = type(dados).__name__ +filename = tempfile.mktemp(prefix="pyboleto-", suffix=".pdf") +boleto = BoletoPDF(filename, True) +boleto.drawBoleto(dados) +boleto.nextPage() +boleto.save() + +generated = filename + '.xml' +pdftoxml(filename, generated) +# expected = _get_expected(bank, generated) +# diff = diff_pdf_htmls(expected, generated) +# os.unlink(generated) +# os.unlink(filename) +# if diff: +# print("Error while checking xml for %r:\n%s" % (bank, diff)) diff --git a/tests/xml/BoletoBs2-expected.xml b/tests/xml/BoletoBs2-expected.xml new file mode 100644 index 0000000..e69de29 From 9536f28f3d6e7c00f1783ddc4423c906be3e53d7 Mon Sep 17 00:00:00 2001 From: Defendi Date: Tue, 25 May 2021 12:07:55 -0300 Subject: [PATCH 5/6] =?UTF-8?q?Inclus=C3=A3o=20do=20banco=20BS2=20no=20rea?= =?UTF-8?q?dme?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 6d39b05..ee585f0 100644 --- a/README.rst +++ b/README.rst @@ -65,6 +65,8 @@ Por enquanto, são essas que temos. +----------------------+----------------+-----------------+------------+ | **Cecred** | 1 | Yes | Yes | +----------------------+----------------+-----------------+------------+ + | **BS2** | 1 | Yes | Yes | + +----------------------+----------------+-----------------+------------+ .. _pyboleto-docs: From 2d7766bfcd53ba674960698d8f64aba852c990ea Mon Sep 17 00:00:00 2001 From: Defendi Date: Fri, 9 Jul 2021 19:06:52 -0300 Subject: [PATCH 6/6] =?UTF-8?q?Texto=20de=20Instru=C3=A7=C3=A3o?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pyboleto/pdf.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pyboleto/pdf.py b/pyboleto/pdf.py index 7711e22..9f6089c 100644 --- a/pyboleto/pdf.py +++ b/pyboleto/pdf.py @@ -539,7 +539,7 @@ def _drawReciboCaixa(self, boleto_dados, x, y): self.pdf_canvas.drawString( 0, y + self.delta_title, - 'Instruções' + 'Informações de Responsabilidade do Beneficiário' ) self.pdf_canvas.setFont('Helvetica', self.font_size_value)