Ali khan
Ali khan

Reputation: 195

How to make a file downloadable in Odoo Python?

I have created a wizard in my module that generate static Excel report, it works well. The problem is that there are clients who access my module remotely, when they open wizard and click on button the generated report saves on my local drive and they get nothing, is there any solution that I make my XLSX report as a downloadable file and the clients can download it directly ?

This is what I have tried but it didn't work:

data = wizard.plugin_file
file_path = wizard.file_path
my_report_data = open('C:/Users/Report.xlsx','rb')
f = my_report_data.read()
output = base64.encodestring(f)
self.write(cr, uid, ids[0], {'plugin_file': output}, context = context)
view_obj = self.pool.get('ir.ui.view')
view_id = view_obj.search(cr, uid, [('model', '=', 'report.model'), \
                            ('name', '=', 'report_model_form_view2')])

return {
    'name': 'Monthly Report ',
    'view_type': 'form',
    'view_mode': 'form',
    'res_model': 'report.model',
    'view_id': view_id, 'form'
    'res_id': ids[0],
    'type': 'ir.actions.act_window',
    'target': 'new',
    'context': context,
}

Form:

<field name="file_path" invisible="1"/>
<field name="plugin_file" filename="file_path"/>

Upvotes: 2

Views: 3407

Answers (3)

ChesuCR
ChesuCR

Reputation: 9630

With Odoo 11 you can do the following:

  1. Create the binary field and the filename:

    mock_pdf = fields.Binary(string='Mock pdf')
    
    mock_pdf_filename = fields.Char(
        string='Mock PDF Filename',
        compute='_compute_mock_pdf_filename'
    )
    
    @api.depends('mock_pdf')
    def _compute_mock_pdf_filename(self):
        self.ensure_one()
        self.mock_pdf_filename = self.name + '.pdf'
    
  2. Then you can create a button to generate the pdf file with the method render_qweb_pdf (or any other file). Then encode in base64 in order to add the content to the binary file. In your case the file was already somewhere in the system.

    @api.multi
    def print_bg_reports(self):
        self.ensure_one()
        ir_actions_report = self.env['ir.actions.report']
    
        report_type = 'qweb-pdf'
        report_name = 'module_name.report_name'
    
        pdf_content = ir_actions_report.search([
            ('report_name', '=', report_name),
            ('report_type', '=', report_type)
        ], limit=1).render_qweb_pdf(self.id)
        self.mock_pdf = base64.encodestring(pdf_content[0])
    
  3. Finally add the button and the binary fields to the form:

    <field name="mock_pdf_filename" invisible="1" />
    <field name="mock_pdf" filename="mock_pdf_filename" />
    <button name="print_bg_reports" type="object" string="Print reports in background" />
    

Note: Actually I do not know how you create the xlsx report. If you create it with the report_xlsx module you can do almost the same just replacing the report type. If not, you just need to convert the local file to base64 and assign the value to the binary field. One last option would be to create one attachment in the record, take a look to this other answer that I have written in order to create it

Upvotes: 0

Adrian Merrall
Adrian Merrall

Reputation: 2499

The typical pattern for this is:

  1. Create a field on your wizard model of type binary and put it on your form.

    'report_result': fields.binary('Download File',readonly=True),

  2. When you have generated your report, base64 encode it and write it back to the wizard.

    output = base64.encodestring(my_report_data) self.write(cr, uid, ids[0], {'report_result': output}, context = context)

  3. Return a window action so the pop-up re-displays. The data field will now be a download field they can click.

    return { 'type': 'ir.actions.act_window', 'res_model': 'my.report.model', 'view_mode': 'form', 'view_type': 'form', 'res_id': wizard.id, 'target': 'new', }

For bonus points, you can control the name of the downloaded file so it is unique or has the partner name or date in the file name for example. Create a char or functional field on your wizard and write the file name into it at the same time you write the report result. Then when you define the report result field on your form, include the name as an attribute like this.

<field name="my_file_name_field" invisible="1"/>
<field name="report_result" filename="my_file_name_field"/>

Upvotes: 1

OmaL
OmaL

Reputation: 5044

Following code was working fine when exporting csv files.

import cStringIO
import base64
def your_export_function(self):
    fd = cStringIO.StringIO()
    #use this file descriptor instead of file path
    #after loading everydata to your file discriptor
    out = base64.encodestring(fd.getvalue())
    fd.close()        
    self.write(cr, uid, ids, { 'data':out}, context=context) #data is the binary field in openerp

Upvotes: 1

Related Questions