Any update on printing reports?

Tried to create an action button to print a report using ChatGPT.

But for this one I need a Python Library called reportlab to generate a PDF report

from reportlab.pdfgen import canvas

def printReport(actions):
    report = canvas.Canvas("training_report.pdf")
    for action in actions:
        table_name = action[1]
        if table_name == "Func_x_Treinamento":
            record = action[2]
            treino_id = record["Treino"]
            treino = Treinamentos.getRecord(treino_id)
            report.drawString(100, 750, "Relatório de Treinamento")
            report.drawString(100, 700, "Título: " + treino["Titulo"])
            report.drawString(100, 650, "Data: " + treino["Data"])
            # Add other details of the training to the report
            funcionarios = Funcionarios.lookupRecords(id__in=existing_treinamentos_funcionarios)
            report.drawString(100, 600, "Funcionários Participantes:")
            y_offset = 550
            for funcionario in funcionarios:
                report.drawString(100, y_offset, funcionario["Nome"])
                y_offset -= 50
    report.showPage()
    report.save()

actions = []
existing_treinamentos_funcionarios = set(Func_x_Treinamento.lookupRecords(Treino=$id))
count = 0
for e in existing_treinamentos_funcionarios:
    actions.append(["GenerateReport", "Func_x_Treinamento", {
      "Treino": $id
    }])
    count += 1
if actions:
    return {
      "button": "Gerar Relatório",
      "description": 'Gerar relatório de {} funcionarios para treinamento "{}"'.format(count, $Titulo),
      "actions": actions,
      "onClick": "printReport"
    }
else:
    return {
      "button": "Zero Registros",
      "description": "Zero Registros",
      "actions": actions
    }

Then I asked it to change it to create a HTML report. Then it asks for “jinja2” library.

As I told I had no Jinja, it generated a plain HTML string using Python… but it needs a JavaScript function to open it in a new window.

Any other easier solution?

Once you have your formula return valid HTML, you might use the HTML Viewer Widget to view it. Then, in the frame of the widget, right-click > “This frame” > “Print frame…” (I’m guessing the translations, because I’m French!). Example here.

Capture vidéo du 2023-01-30 21-42-56(2)

2 Likes

Thanks, but the formula right now is creating HTML in the memory only I guess, as the it’s created with a button. I guess I need the button to write the HTML to another cell, then the HTML viewer to be linked to that cell?

Why bother with a button ? If you replace your “action cell” by an “html cell” whose formula returns the variable containing the HTML, the HTML Viewer doesn’t need a button.

Created this formula for a start (only the details of the Treinamento, not the assigned employees), but the HTML viewer is returning blank.

def generate_html_report(record):
  html_template = """
  <html>
    <head>
      <title>{0}</title>
    </head>
    <body>
      <h1>{0}</h1>
      <p><strong>Description:</strong> {1}</p>
      <p><strong>Location:</strong> {2}</p>
      <p><strong>Date and Time:</strong> {3}</p>
      <p><strong>Instructor:</strong> {4}</p>
      <p><strong>Evaluation Method:</strong> {5}</p>
    </body>
  </html>
  """.format(record['Titulo'], record['Descricao'], record['Local'], 
             record['Data_e_hora'], record['Instrutor'], 
             record['Forma_de_Avaliacao'])
  
  return html_template

You should try as follows:

return """
  <html>
    <head>
      <title>{0}</title>
    </head>
    <body>
      <h1>{0}</h1>
      <p><strong>Description:</strong> {1}</p>
      <p><strong>Location:</strong> {2}</p>
      <p><strong>Date and Time:</strong> {3}</p>
      <p><strong>Instructor:</strong> {4}</p>
      <p><strong>Evaluation Method:</strong> {5}</p>
    </body>
  </html>
""".format(
  $Titulo,
  $Descricao,
  $Local,
  $Data_e_hora,
  $Instrutor,
  $Forma_de_Avaliacao
)

In your code, you where defining a generate_html_report function that had an internal variable html_template, then returning an external variable html_template without calling the function itself: so it was technically empty, hence the blank report.

Either ChatGPT is not the threat to programmers that many thought it would be, or I am so dumb that I am giving the worst prompts ever, but most code it generates leads me to nowhere. I am trying now to append below the header with the training info, the employees selected to that training. The result rfom ChatGDP gets me an error code that Funcionarios (employees) is not defined.

> return """
>   <html>
>     <head>
>       <title>{0}</title>
>     </head>
>     <body>
>       <h1>{0}</h1>
>       <hr>
>       <table width="100%">
>         <tr>
>           <td><strong>Descrição:</strong></td>
>           <td>{1}</td>
>         </tr>
>         <tr>
>           <td><strong>Local:</strong></td>
>           <td>{2}</td>
>         </tr>
>         <tr>
>           <td><strong>Data e Hora:</strong></td>
>           <td>{3}</td>
>         </tr>
>         <tr>
>           <td><strong>Instrutor:</strong></td>
>           <td>{4}</td>
>         </tr>
>         <tr>
>           <td><strong>Método de Avaliação:</strong></td>
>           <td>{5}</td>
>         </tr>
>       </table>
>       <hr>
>       <table width="100%">
>         <tr>
>           <th>#</th>
>           <th>Nome</th>
>           <th>Função</th>
>           <th>Presença</th>
>         </tr>
>         {6}
>       </table>
>     </body>
>   </html>
> """.format(
>   $Titulo,
>   $Descricao,
>   $Local,
>   $Data_e_hora,
>   $Instrutor,
>   $Forma_de_Avaliacao,
>   '\n'.join(
>     ["<tr><td>{0}</td><td>{1}</td><td>{2}</td><td></td></tr>".format(i+1, func[0], func[1]) for i, func in enumerate(funcionarios)]
>   )
> )

For having tried it, ChatGPT is quite impressive to accelerate development, but it frequently leaves errors to be corrected. What’s impressive too is that, if you tell it which error it did, it will correct it.

As is, I’m guessing you have a Funcionarios column? Would you have a sample you could share on docs.getgrist.com? This would make it easier to investigate, especially if you share it with public editor access.

1 Like

:flushed: :flushed:

remind me again how to make the document public on doc.getgrist.com?

1 Like

done.
https://pavicon.getgrist.com/oXwn9Bcg5tgo/Treinamentos

Just done. I’ve set an “x” mark for presents, which you may change. You may hide the HTML column, to have good formatting of the table.

Here is the final formula:

f = Func_x_Treinamento.lookupRecords(Treino=$id)
return """
  <html>
    <head>
      <title>{0}</title>
    </head>
    <body>
      <h1>{0}</h1>
      <hr>
      <table width="100%">
        <tr>
          <td><strong>Descrição:</strong></td>
          <td>{1}</td>
        </tr>
        <tr>
          <td><strong>Local:</strong></td>
          <td>{2}</td>
        </tr>
        <tr>
          <td><strong>Data e Hora:</strong></td>
          <td>{3}</td>
        </tr>
        <tr>
          <td><strong>Instrutor:</strong></td>
          <td>{4}</td>
        </tr>
        <tr>
          <td><strong>Método de Avaliação:</strong></td>
          <td>{5}</td>
        </tr>
      </table>
      <hr>
      <table width="100%">
        <tr>
          <th>#</th>
          <th>Nome</th>
          <th>Função</th>
          <th>Presença</th>
        </tr>
        {6}
      </table>
    </body>
  </html>
""".format(
  $Titulo,
  $Descricao,
  $Local,
  $Data_e_hora,
  $Instrutor,
  $Forma_de_Avaliacao,
  '\n'.join((
    "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>".format(
      i+1,
      func.Funcionario.Nome,
      func.Funcionario.Funcao,
      func.Presenca and "x" or "",
    ) for i, func in enumerate(f)
  ))
)
1 Like

I edited your code after including more fields, etc.

Only thing I am failing is to make the table rows height smaller. Changed padding, height, etc, all fails. It’s like if the cells still had some hidden feature causing the space between them. Reducing the row height is specially important in the whole page header.

f = Func_x_Treinamento.lookupRecords(Treino=$id)
return """
  <html>
    <head>
      <title>RELAÇÃO DE FREQUÊNCIA DE TREINAMENTOS</title>
    </head>
    <body>
      <h3><center>RELAÇÃO DE FREQUÊNCIA DE TREINAMENTOS</center></h3>
      <hr>
      <table width="100%"><border-spacing: 5px table border="1" padding-top="0" padding-bottom="0" cellspacing="0" style="border-collapse:collapse;">
        <tr height="10px" padding-top="0" padding-bottom="0">
          <td width="30%"><strong>Treinamento:</strong></td>
          <td><p style="font-size: 12px">{0}</p></td>
        </tr>
        <tr height="10px" padding-top="0" padding-bottom="0">
         <td width="30%"><strong>Conteúdo Programático:</strong></td>
         <td><p style="font-size: 12px">{1}</p></td>
        </tr>
        <tr height="10px" padding-top="0" padding-bottom="0">
         <td width="30%"><strong>Objetivo:</strong></td>
         <td><p style="font-size: 12px">{2}</p></td>
        </tr>
        <tr>
         <td width="30%"><strong>Funções Requisitadas:</strong></td>
         <td><p style="font-size: 12px">{3}</p></td>
        </tr>
      </table>
      <table width="100%"><border-spacing: 5px table border="1" padding-top="0" padding-bottom="0" cellspacing="0" style="border-collapse:collapse;">
        <tr height="10px">
          <td width="30%"><strong>Tipo Treinamento:</strong></td>
          <td><p style="font-size: 12px">{6}</p></td>
          <td width="30%"><strong>Local:</strong></td>
          <td><p style="font-size: 12px">{9}</p></td>
          <td width="20%"><strong>Data e Hora</strong></td>
          <td><p style="font-size: 12px">{10}</p></td>
        </tr>
        <tr height="10px">
          <td width="30%"><strong>Duração (horas):</strong></td>
          <td><p style="font-size: 12px">{4}</p></td>
          <td width="20%"><strong>Assinaturas?</strong></td>
          <td><p style="font-size: 12px">{5}</p></td>
          <td width="30%"><strong>Instrutor:</strong></td>
          <td><p style="font-size: 12px">{7}</p></td>
        </tr>
        <tr height="10px">
          <td width="30%"><strong>Tipo Avaliação:</strong></td>
          <td><p style="font-size: 12px">{8}</p></td>
          <td width="30%"><strong>Prazo Avaliação:</strong></td>
          <td><p style="font-size: 12px">{6}</p></td>
        </tr>
      </p>  
      </table>
      <hr>
      <table width="100%"><table border="1" cellpadding="3" cellspacing="0" style="border-collapse:collapse;">
        <tr>
          <th width="5%">#</p></th>
          <th width="45%">Nome</th>
          <th width="45%">Função</th>
          <th width="5%">Presença</th>
        </tr>
        {12}
      </table>
    </body>
  </html>
""".format(
  $Titulo,
  $Conteudo_Programatico,
  $Objetivo,
  $Funcoes_Setores_Requisitados,
  $Num_Horas,
  $Necessidade_Assinatura_,
  $Tipo_de_Treinamento,
  $Instrutor,
  $Forma_de_Avaliacao,
  $Local,
  $Data_e_hora,
  $Forma_de_Avaliacao,
  '\n'.join((
    "<tr><td>{0}</td><td>{1}</td><td>{2}</td><td>{3}</td></tr>".format(
      i+1,
      func.Funcionario.Nome,
      func.Funcionario.Funcao,
      func.Presenca and "x" or "",
    ) for i, func in enumerate(f)
  ))
)

see, too much space between rows and lines. And everytime I try to use a “style” in the html for the whole document, I get an error message.

I also tried to change LINE HEIGHT, but then it also makes the space between two lines in the same row too small, so the lines get one above the other.

Thank you very much for your help JPeron.

One problem is that most help I find on the web regarding HTML and even from ChatGPT is that they suggest using a style section, but whever I try to use it I get errors.

Just as an example of Grist HTML giving me an error whenever I try to add a STYLE…

I tried to add headers to each bage and page breaks in the tables, according to this post

<style type="text/css">
    table { page-break-inside:auto }
    tr    { page-break-inside:avoid; page-break-after:auto }
    thead { display:table-header-group }
    tfoot { display:table-footer-group }
</style>

and get this error. Everything I try to put at style get’s me “KeyError” because the value is not found in a Python dict.

Curly braces need to be escaped by doubling them in format strings:

<style type="text/css">
    table {{ page-break-inside:auto }}
    tr    {{ page-break-inside:avoid; page-break-after:auto }}
    thead {{ display:table-header-group }}
    tfoot {{ display:table-footer-group }}
</style>

About css shenanigans, honestly, I don’t know the miracle to avoid that pain each time one has to create a new page style: I struggle with it myself on any new project I launch.

1 Like

And once again you saved me.

But it’s incredible that I am doing everything in order to make the cells closer but nothing works. The result is that the form on top (training info) is occupying over half the page. Well, this is an HTML problem. I might as well post anywhere else, instead of bothering you anymore JPeron. Thank you very much for all the help you already gave.

EDIT : found the problem. It’s the

that appears on several rows and cells.

ah, much better

1 Like