Open lucascollina opened 8 years ago
Olá Lucas, eu acabei de implementar isso em meu projeto. Vou colocar o código em meu github e te manda
@aasf86 Mande o código para o repositorio aqui do projeto. Faça um PR.
Olá Carlos, bom o que fiz foi um verdadeiro POG pra resolver isso, não sei se vale a pena estar no projeto. O 'boletoBancario.MontaBytesPDF()' estava demorando muito pra retornar os bytes. Aí tive que apelar para a linha de comando usando o http://wkhtmltopdf.org/ e que foi muito, mas muito mais rápido. voce já deve estar imaginando o que fiz né, sim eu fiz isso rsrsrs. Vou preparar o codigo e repasso. Abraços
@aasf86 O problema de linha de comando é com aplicação web.
Eu gostaria da ajuda de vocês com essa questão de vários boletos no mesmo PDF, eu até consegui um modo de fazer em web em que eu Monto o HTML de todos os Boletos e Mando para View por uma ViewBag uso a Rotativa PDF para fazer o PDF porém os Boletos Ficam todos Amontoados sem quebra de Página e não centralizam também .
@EltonRst eu solucionei da seguinte forma:
Dim htmlBoletos As New StringBuilder
htmlBoletos.Append("<div style=""page-break-after: always;"">")
htmlBoletos.Append(htmlBoleto)
htmlBoletos.Append("</div>")
Se quiser centralizar o boleto é só acrescentar no style da div "margin: 0 auto;".
O meu maior problema hoje está sendo a demora na montagem do PDF da mesma forma que o nosso amigo @aasf86 reportou.
Alguém conseguiu solucionar?
@lucascollina Eu Fiz da seguinte forma No Controller em C#:
public ActionResult Boletos()
{
List<BoletoBancario> Boletos = new List<BoletoBancario>(); // Crio a Lista e Adiciono
//todos os boletos pulei essa parte do cógido por que é massante, dai após:
string html = string.Empty;
foreach (BoletoBancario boleto in Boletos)
{
html += string.Concat("<center>", boleto.MontaHtml(), "</center>");
}
ViewBag.Boletos = html;
var pdf = new ViewAsPdf /// Essa é a Parte do Rotativa PDF
{
ViewName = "_Boletos",
FileName = "Boletos.pdf",
PageSize = Size.A4,
IsGrayScale = true,
PageMargins = new Margins { Bottom = 15, Left = 5, Right = 5, Top = 10 }
};
return File(pdf.BuildPdf(this.ControllerContext), "application/pdf");
}
/// Já na View fiz Assim
@{
Layout = null;
}
<html lang="pt-br">
<head>
<meta charset="utf-8" />
<title>Boletos</title>
<style type="text/css">
@@media print { //@@ Por causa do Razor do MVC mas no css é só @
body > center {
page-break-after: always;
}
body > center:last-child {
page-break-after: always;
}
}
</style>
</head>
<body>
@Html.Raw(ViewBag.Boletos)
</body>
</html>
Funciona Perfeitamente, testei com 10 boletos, cerca de 2 segundos, só o boleto fica menor, as margens da direita e da esquerda ficam com 2 dedos de largura em branco mas de boa.
@lucascollina estou implementando algumas Melhorias no Projeto Boleto.Net para podermos gerar os boletos em lote. assim que eu tiver algo eu te aviso, mas esse ai de cima funciona porém não ocupa toda a largura da folha e usa mais essa biblioteca chamada Rotativa PDF, mas quebra o galho.
Esse Rotativa só funciona em MVC?
Lucas, foi mal cara, ainda não te enviei por que estou muito corrido cara, esta semana eu dou um jeito de te enviar cara. @lucascollina
@lucascollina Apenas em MVC, ela não converte somente o HTML, quem faz isso é o NReco PDF, que inclusive está incluso no projeto do Boleto.Net, Estou trabalhando em uma possível solução para a quebra de página a cada boleto, já conseguí alterar o Boleto.Net para Receber uma lista de Boletos, o resto é rápido.
@lucascollina Consegui Finalmente fazer as alterações no Projeto Boleto.Net segue o Método Utilizado na Classe BoletoBancario.cs
/// <summary>
/// Lista de Boletos, objetos do tipo
/// BoletoBancario
/// </summary>
/// <param name="boletos">Lista de Boletos, objetos do tipo BoletoBancario</param>
/// <param name="tituloNaView">Título Que aparecerá na Aba do Navegador</param>
/// <param name="convertLinhaDigitavelToImage">bool Converter a Linha Digitavel Em Imagem</param>
/// <returns>byte[], Vetor de bytes do PDF</returns>
public byte[] MontaBytesListaBoletosPDF(List<BoletoBancario> boletos, string tituloNaView = "", bool convertLinhaDigitavelToImage = false)
{
string htmlHead = string.Concat(
"<html>",
"<head><title>", tituloNaView, "</title>",
"<style type='text/css' media='screen,print'>",
".break{ display: block; clear: both; page-break-after: always;}",
"</style>",
"</head>",
"<body>"
);
string htmlBoletos = string.Empty;
foreach (BoletoBancario boleto in boletos)
{
htmlBoletos += string.Concat("<div class='break'>", boleto.MontaHtmlEmbedded(convertLinhaDigitavelToImage, true), "</div>");
}
string htmlFooter = "</body></html>";
return (new NReco.PdfGenerator.HtmlToPdfConverter()).GeneratePdf(string.Concat(htmlHead, htmlBoletos, htmlFooter));
}
Só implementar esse Método no seu Boleto.Net, Compliar e Utilizar a DLL Eu Implementei ele Logo Baixo do Método original
public byte[] MontaBytesPDF(bool convertLinhaDigitavelToImage = false)
{
return (new NReco.PdfGenerator.HtmlToPdfConverter()).GeneratePdf(this.MontaHtmlEmbedded(convertLinhaDigitavelToImage, true));
}
Modo de Uso:
public ActionResult Boletos()
{
// Lista que Receberá os Boletos
List<BoletoBancario> Boletos = new List<BoletoBancario>();
/// Monte seus Boletos Bancários e Adicione Na lista depois Divirta-se
return File(new BoletoBancario().MontaBytesListaBoletosPDF(Boletos, "Boletos Bancários"), "application/pdf", "Boletos.pdf");
}
Caso queira também pode baixar Minha DLL Compilada http://eltonrst.serveblog.net/Upload/downloader.php?Arquivo=Boleto.Net.zip Aqui o Arquivo BoletoBancario.cs http://eltonrst.serveblog.net/Upload/downloader.php?Arquivo=BoletoBancario.zip
Eu só começei a usar o Boleto.Net por que eu preciso de um pouco de agilidade no trabalho, só estou usando para gerar os Boletos em PDF mesmo, pra Remessa / Retorno eu Mesmo Desenvolví meus Layouts de Banco, Estou no Processo de Validação, por eunquanto eu tenho o Itau e o BB Validados.
@EltonRst Obrigado pela postagem, será de grande ajuda.
Entretanto, estou com problemas referente ao tamanho do boleto.
Ao gerar o arquivo PDF o boleto não ocupa a página toda.
Teve esse problema também? Ou da forma como você implementou o boleto fica certo?
Posso dar uma sugestão, na parte do código abaixo prq não alteram para stringbuilder? Por exemplo minha aplicação por volta de uns 1000 boletos por vez, fazendo essa alteração tive uma melhora na performance.
htmlBoletos += string.Concat("
@lucascollina da forma que implementei os boletos ficam corretos, utilizei a mesma lógica do modo original que gerava 1 boleto só, para gerar todos os boletos, vou deixar um link abaixo para você com um
gerado por mim.
@Westfallx , essa questão depende muito do seu hardware, e do tipo de de desempenho que você quer extrair dele, usando o StringBuilder
que é um objeto que no final das contas monta sua string do mesmo modo, faz com que você economize memória RAM, mas perca mais desempenho em
processamento, já o
string.concat()
acaba que usa muita memória, mas o processamento cai pela metade, elas por elas, dependendo do hardware que sustenta faz a diferença sim.
mas qualquer ajuda é bem-vinda, você pode alterar o quanto quiser. a final estamos aqui para Nos Ajudar, qualquer sugestão, duvida ou argumentação eu agradeço, pois estou aprendendo com vocês. grato !
@lucascollina & @Westfallx segue a correção do Projeto Boleto.Net
:
Classe Boleto.Net.BoletoBancario.cs
Acabei por testar o StringBuilder
e ganhei cerca de 4 Segundos
de desempenho em relação ao string.Concat()
Além de ficar mais organizado e mais legível, só o Processamento foi de 15%
para 37%
mas a memória RAM caiu de 70 MB
para 20 MB
public byte[] MontaBytesPDF(bool convertLinhaDigitavelToImage = false)
{
return (new NReco.PdfGenerator.HtmlToPdfConverter()).GeneratePdf(this.MontaHtmlEmbedded(convertLinhaDigitavelToImage, true));
}
/// <summary>
/// Lista de Boletos, objetos do tipo
/// BoletoBancario
/// </summary>
/// <param name="boletos">Lista de Boletos, objetos do tipo BoletoBancario</param>
/// <param name="tituloNaView">Título Que aparecerá na Aba do Navegador</param>
/// <param name="CustomSwitches">Custom WkHtmlToPdf global options</param>
/// <param name="tituloPDF">Título No Início do PDF</param>
/// <param name="PretoBranco">Preto e Branco = true</param>
/// <param name="convertLinhaDigitavelToImage">bool Converter a Linha Digitavel Em Imagem</param>
/// <returns>byte[], Vetor de bytes do PDF</returns>
public byte[] MontaBytesListaBoletosPDF(List<BoletoBancario> boletos, string tituloNaView = "", string CustomSwitches = "", string tituloPDF = "", bool PretoBranco = false, bool convertLinhaDigitavelToImage = false)
{
StringBuilder htmlBoletos = new StringBuilder();
htmlBoletos.Append("<html><head><title>");
htmlBoletos.Append(tituloNaView);
htmlBoletos.Append("</title><style type='text/css' media='screen,print'>");
htmlBoletos.Append(".break{ display: block; clear: both; page-break-after: always;}");
htmlBoletos.Append("</style></head><body>");
if (!string.IsNullOrEmpty(tituloPDF))
{
htmlBoletos.Append("<br/><center><h1>");
htmlBoletos.Append(tituloPDF);
htmlBoletos.Append("</h1></center><br/>");
}
foreach (BoletoBancario boleto in boletos)
{
htmlBoletos.Append("<div class='break'>");
htmlBoletos.Append(boleto.MontaHtmlEmbedded(convertLinhaDigitavelToImage, true));
htmlBoletos.Append("</div>");
}
htmlBoletos.Append("</body></html>");
return (new NReco.PdfGenerator.HtmlToPdfConverter() { CustomWkHtmlArgs = CustomSwitches, Grayscale = PretoBranco }).GeneratePdf(htmlBoletos.ToString());
}
Se alguém quiser fazer um Pull Request para incrementar no projeto ficarei feliz, pois não tenho como fazer o commit ou request
Segue um exemplo bem tosco de uso:
Esses CustomSwitches
são opções globais customizáveis do wkhtmltopdf
string CustomSwitches = string.Format(
"--print-media-type --header-line --header-font-size \"11\" --header-spacing 2 --header-font-name \"calibri light\" --header-center \"{0}\" --header-right \"Data: [date] [time]\" " +
"--footer-left \"{1}\" --footer-right \"Página: [page] de [toPage]\" --footer-line --footer-font-size \"9\" --footer-spacing 2 --footer-font-name \"calibri light\" ",
"Empresa do Seu Cliente", "Sua Empresa");
return File(new BoletoBancario().MontaBytesListaBoletosPDF(Boletos, "Boletos Bancários", CustomSwitches, "Boletos Bancários"), "application/pdf", "Boletos.pdf");
@EltonRst Ficou show essa solução. Parabéns para o pessoal que resolveu essa questão ! 😄
pessoal bom dia! em que momento chamo a rotina para gerar o pdf
@fmfabiano
public ActionResult Boletos()
{
// Lista que Receberá os Boletos
List
/// Monte seus Boletos Bancários e Adicione Na lista depois Divirta-se
return File(new BoletoBancario().MontaBytesListaBoletosPDF(Boletos, "Boletos Bancários"), "application/pdf", "Boletos.pdf");
}
o que realmente interessa: new BoletoBancario().MontaBytesListaBoletosPDF(Boletos, "Boletos Bancários")
Bom dia, Gostaria de saber se é possível alterar o output path da geração do boleto. Aparentemente quando o pdf é gerado, ele é gerado na pasta bin. Quando o IIS detecta qualquer mudança nessa pasta ele recarrega tudo, derruba sessão, chama applicaton_end e etc. Em resumo, toda vez que eu gero um pdf do boleto o IIS derruba a sessão de todos e recarrega tudo.
Olá Pessoal, sou novo nisso , estou com muita dificuldade nessa parte de gerar o boleto. a parte do html no meu código esta funcionando normalmente, mas não to sabendo exportar para pdf. :( vi que temos dois metodos na classe boletobancario:
MontaBytesListaBoletosPDF MontaBytesPDF
mas não estou sabendo usar nenhum dos dois :(
será que alguem poderia me enviar um exemplo de usabilidade?
desde ja agradeço.
segue um trecho do nosso código logo :
`public string HTMLParaImpressao() { BoletoNet.BoletoBancario pre = preImpressao();
return pre.MontaHtmlEmbedded();
}
public bite HtmlParaPdf()
{
BoletoNet.BoletoBancario pre = preImpressao();
return pre.MontaBytesPDF();
}
private BoletoNet.BoletoBancario preImpressao()
{
BoletoBancario boletoRetorno = new BoletoBancario();
DateTime vencimento = DateTime.Now.AddDays(5);
Cedente c = new Cedente(CNPJ_CEDENTE, RAZAO_SOCIAL_CEDENTE, AGENCIA_CEDENTE, CONTA_CEDENTE);
c.Codigo = CodigoConvenio;
BoletoNet.Boleto b = new BoletoNet.Boleto(DataVencimento, ValorBoleto, CARTEIRA, NossoNumero.ToString(), c);
#region Adiciona Instruções somente no Cedente
//IInstrucao instrucaoCedente = new Instrucao(33);
//instrucaoCedente.Descricao = InstrucoesCaixa;
//c.Instrucoes.Add(instrucaoCedente);
#endregion
b.NumeroDocumento = SeuNumero;
b.Sacado = new Sacado(CnpjSacado, RazaoSocialSacado);
b.Sacado.Endereco.End = EnderecoSacado + " " + NumeroSacado + " " + ComplementoSacado;
b.Sacado.Endereco.Bairro = BairroSacado;
b.Sacado.Endereco.Cidade = CidadeSacado;
b.Sacado.Endereco.CEP = CepSacado;
b.Sacado.Endereco.UF = UfSacado;
#region Adiciona Instruções somente no Sacado
//IInstrucao instrucaoSacado = new Instrucao(33);
//instrucaoSacado.Descricao = InstrucoesCaixa;
//b.Sacado.Instrucoes.Add(instrucaoSacado);
#endregion
#region Adiciona Instruções comuns - Cedente e Sacado
IInstrucao instrucaoComum = new Instrucao(33);
instrucaoComum.Descricao = InstrucoesCaixa;
b.Instrucoes.Add(instrucaoComum);
#endregion
//Espécie Documento - [R] Recibo
b.EspecieDocumento = new EspecieDocumento_Santander("17");
b.LinhaDigitavelVindaDoBanco = LinhaDigitavel;
b.CodigoDeBarrasVindaDoBanco = CodigoDeBarras;
boletoRetorno.CodigoBanco = short.Parse(CodigoBanco);
boletoRetorno.Boleto = b;
boletoRetorno.MostrarCodigoCarteira = true;
boletoRetorno.MostrarComprovanteEntrega = false;
boletoRetorno.Boleto.Valida();
return boletoRetorno;
}
private static T ToEnum<T>(string value, bool ignoreCase, T defaultValue) where T : struct
{
if (string.IsNullOrEmpty(value))
return defaultValue;
T result;
if (Enum.TryParse(value, ignoreCase, out result))
return result;
return defaultValue;
}`
@douglasacioli
Olá Pessoal, sou novo nisso , estou com muita dificuldade nessa parte de gerar o boleto. a parte do html no meu código esta funcionando normalmente, mas não to sabendo exportar para pdf. :( vi que temos dois metodos na classe boletobancario:
MontaBytesListaBoletosPDF MontaBytesPDF
mas não estou sabendo usar nenhum dos dois :(
será que alguem poderia me enviar um exemplo de usabilidade?
desde ja agradeço.
segue um trecho do nosso código logo :
`public string HTMLParaImpressao() { BoletoNet.BoletoBancario pre = preImpressao();
return pre.MontaHtmlEmbedded(); } public bite HtmlParaPdf() { BoletoNet.BoletoBancario pre = preImpressao(); return pre.MontaBytesPDF(); } private BoletoNet.BoletoBancario preImpressao() { BoletoBancario boletoRetorno = new BoletoBancario(); DateTime vencimento = DateTime.Now.AddDays(5); Cedente c = new Cedente(CNPJ_CEDENTE, RAZAO_SOCIAL_CEDENTE, AGENCIA_CEDENTE, CONTA_CEDENTE); c.Codigo = CodigoConvenio; BoletoNet.Boleto b = new BoletoNet.Boleto(DataVencimento, ValorBoleto, CARTEIRA, NossoNumero.ToString(), c); #region Adiciona Instruções somente no Cedente //IInstrucao instrucaoCedente = new Instrucao(33); //instrucaoCedente.Descricao = InstrucoesCaixa; //c.Instrucoes.Add(instrucaoCedente); #endregion b.NumeroDocumento = SeuNumero; b.Sacado = new Sacado(CnpjSacado, RazaoSocialSacado); b.Sacado.Endereco.End = EnderecoSacado + " " + NumeroSacado + " " + ComplementoSacado; b.Sacado.Endereco.Bairro = BairroSacado; b.Sacado.Endereco.Cidade = CidadeSacado; b.Sacado.Endereco.CEP = CepSacado; b.Sacado.Endereco.UF = UfSacado; #region Adiciona Instruções somente no Sacado //IInstrucao instrucaoSacado = new Instrucao(33); //instrucaoSacado.Descricao = InstrucoesCaixa; //b.Sacado.Instrucoes.Add(instrucaoSacado); #endregion #region Adiciona Instruções comuns - Cedente e Sacado IInstrucao instrucaoComum = new Instrucao(33); instrucaoComum.Descricao = InstrucoesCaixa; b.Instrucoes.Add(instrucaoComum); #endregion //Espécie Documento - [R] Recibo b.EspecieDocumento = new EspecieDocumento_Santander("17"); b.LinhaDigitavelVindaDoBanco = LinhaDigitavel; b.CodigoDeBarrasVindaDoBanco = CodigoDeBarras; boletoRetorno.CodigoBanco = short.Parse(CodigoBanco); boletoRetorno.Boleto = b; boletoRetorno.MostrarCodigoCarteira = true; boletoRetorno.MostrarComprovanteEntrega = false; boletoRetorno.Boleto.Valida(); return boletoRetorno; } private static T ToEnum<T>(string value, bool ignoreCase, T defaultValue) where T : struct { if (string.IsNullOrEmpty(value)) return defaultValue; T result; if (Enum.TryParse(value, ignoreCase, out result)) return result; return defaultValue; }`
Esse objeto que retorna do método
BoletoNet.BoletoBancario preImpressao()
você adiciona em uma lista:List<BoletoNet.BoletoBancario> Boletos = new List<BoletoNet.BoletoBancario>();
Depois você pode utilizar:
public ActionResult Boletos()
{
// Lista que Receberá os Boletos
List
/// Monte seus Boletos Bancários e Adicione Na lista depois Divirta-se
return File(new BoletoBancario().MontaBytesListaBoletosPDF(Boletos, "Boletos Bancários"), "application/pdf", "Boletos.pdf");
}
o que realmente interessa: new BoletoBancario().MontaBytesListaBoletosPDF(Boletos, "Boletos Bancários")
Boa tarde a todos!
Vocês tem algum exemplo de como gerar o html de vários boletos de uma única vez?
Ou também poderia ser a criação de um único PDF com todos os boletos.
Agradeço o contato!