1

I am trying to create a route in Odoo 10 to download a binary file for gtfs real-time updater.

I searched in Odoo documentation but I didn't find any similar

This is my controller for test download binary file:

class GtfsRt(http.Controller):
    @http.route('/gtfs_rt', type='http', auth='public')
    def index(self):
        f = open('my_file', 'w+b')
        byte_arr = [120, 3, 255, 0, 100]
        binary_format = bytearray(byte_arr)
        f.write(binary_format)
        f.close()
        return f

I would like to download the file when I go to /gtfs_rt

At this moment I got this error:

Traceback (most recent call last):
  File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 303, in run_wsgi
    execute(self.server.app)
  File "/usr/local/lib/python2.7/dist-packages/werkzeug/serving.py", line 291, in execute
    application_iter = app(environ, start_response)
  File "/opt/odoo/odoo/service/server.py", line 307, in app
    return self.app(e, s)
  File "/opt/odoo/odoo/service/wsgi_server.py", line 186, in application
    return application_unproxied(environ, start_response)
  File "/opt/odoo/odoo/service/wsgi_server.py", line 172, in application_unproxied
    result = handler(environ, start_response)
  File "/opt/odoo/odoo/http.py", line 1326, in __call__
    return self.dispatch(environ, start_response)
  File "/opt/odoo/odoo/http.py", line 1300, in __call__
    return self.app(environ, start_wrapped)
  File "/usr/local/lib/python2.7/dist-packages/werkzeug/middleware/shared_data.py", line 227, in __call__
    return self.app(environ, start_response)
  File "/opt/odoo/odoo/http.py", line 1505, in dispatch
    return response(environ, start_response)
TypeError: 'file' object is not callable
Zoe
  • 27,060
  • 21
  • 118
  • 148
israteneda
  • 705
  • 1
  • 14
  • 26
  • I already made this with flask micro framework and its send_file() function to download the binary file. – israteneda May 22 '19 at 22:15
  • 1
    There are some "complex" examples in Odoo web module. For example the company logo download [here](https://github.com/odoo/odoo/blob/c89da3a68304dc971a642dcfc7eb01663ab6ddf6/addons/web/controllers/main.py#L1098-L1148). As you can see `http.send_file()` is used for the response generation. – CZoellner May 23 '19 at 07:12
  • Thank you for your answer @CZoellner, this is helping me but when I try to run this code: `class GtfsRt(http.Controller): @http.route('/gtfs_rt', auth='public') def index(self, **kw): feed = functools.partial(get_resource_path, 'gtfs_rt', 'static', 'src', 'bin') response = http.send_file(feed(feed)) return response` I get this error: `AttributeError: 'functools.partial' object has no attribute 'startswith'` – israteneda May 31 '19 at 22:26
  • i've never worked with `functools.partial` yet, just create another question with python as tag and your code and error message. – CZoellner Jun 03 '19 at 08:24
  • @CZoellner take a look at my solution, it may be helpful and simpler – ChesuCR Sep 11 '19 at 15:34

3 Answers3

1

This works in Odoo 11 at least. If you have a binary field in any model:

@api.multi
def crete_and_download_dummy_field(self):

    # store here your binary file into the dummy field with base64 enconding

    return {
        'name': 'FEC',
        'type': 'ir.actions.act_url',
        'url': '/web/content/?model=sale.order&id={}&field=dummy&filename_field=dummy_filename&download=true'.format(
            self.id
        ),
        'target': 'self',
    }

If you just want a link to download it in a form you can create a binary file and its name

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()
    name = self.name.replace('/', '_')
    name = name.replace('.', '_')
    name = name + '.pdf'
    self.mock_pdf_filename = name

And in the form

<field name="mock_pdf_filename" invisible="1" />
<field name="mock_pdf" filename="mock_pdf_filename" />
ChesuCR
  • 9,352
  • 5
  • 51
  • 114
0

The following code will download a xml file when goes to a specific route.Hope this will help you.

    xml = # xml contents.
    response = request.make_response(xml,
                                     headers=[('Content-Type', 'application/xml'),
                                              ('Content-Disposition', 'attachment; 
                                                       filename=Xmlreport.xml;')],
                                     cookies={'fileToken': token})


    return response
Ajmal JK
  • 813
  • 4
  • 14
0

I got here while trying to figure out how to download a CSV file without saving it in a field.

Here's how I managed.

from odoo import fields, api, models


class Report(model.TransientModel):

    report_date = fields.Date(required=True)

    @api.multi
    def button_download_csv(self):
        params = urlencode({
            'report_date': self.report_date,
        })

        # this will open the `url` in a new tab
        return {
            'url': f'/custom/reports/?{params}',
            'type': 'ir.actions.act_url'
        }
from io import StringIO

from odoo import http
from odoo.http import request, content_disposition, Response

class CustomerController(http.Controller):

    # auth="public" if login is not required
    @http.route('/custom/reports/', type='http', auth="user", methods=['GET'])
    def customer_report(self, **kw):
        if 'report_date' not in kw:
            return Response('Report date not provided', status=400)

        report_date = kw['report_date']

        # retrieve data from your source
        rows = [
            ('Site', 'Homepage'),
            ('Stack Overflow', 'https://stackoverflow.com/'),
            ('Github', 'https://github.com'),
        ]

        file_ = StringIO()
        result_file = csv.writer(file_)
        result_file.writerows(rows)
        file_.seek(0)

        filename = f'report-{report_date}.csv'
        file_content = file_.getvalue()

        return request.make_response(
            file_content,
            [
                ('Content-Type', 'text/csv;charset=utf8'),
                ('Content-Disposition', content_disposition(filename)),
            ]
        )
omushpapa
  • 1,663
  • 20
  • 25