How to download file from private/files

Hi,

I am creating a text file through a python program, for the purpose of printing labels on barcode printer. The text file is getting created on site1.local/private/files. But, I am not able to view this file in the File List view in the ERPNext web browser. The File list is showing me all the other files under private/files that are uploaded.

Also, when I am trying to manually enter the URL with …/private/files/qrcode.txt, I am getting the 403 forbidden error, saying that “You don’t have permission to access this file”.

Regards
Uma

@UmaG

Have you tried to FTP to the server to download the files or are you using the erpnext.com?

you need to add the tile as “File” Doc as in f = frappe.new_doc("File")

just adding it to filesystem won’t show it under File List.

if you need to download from filesystem and not use File DocType try following :

@frappe.whitelist()
def get_qr_file():
    frappe.local.response.filename = "qrcode.txt"
    frappe.local.response.filecontent = read_file_content('/private/files/qrcode.txt') # custom function
    frappe.local.response.type = "download"
1 Like

Hi @saidsl, @revant_one,

Thanks a lot for responding back so promptly. My code is written in the python file like this:

@frappe.whitelist()
def make_text(args):
save_path = ‘site1.local/private/files’
file_name = os.path.join(save_path, “qrcode.txt”)
f= open(file_name,“w+”)
frappe.msgprint(_(“Doing anything”))
f.write(“^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA”)
f.write(“^PR2,2~SD15^JUS^LRN^CI0^XZ”)
f.write(“^XA^MMT^PW812^LL0406^LS0”)
for rows in summ_data:

	nol = int(number_labels) + 1
	for x in xrange(1, nol):
		f.write("^FT250,79^A0R,28,28^FH\^FD%s^FS" % (rows[0]))
		f.write("^FT533,53^A0R,28,28^FH\^FD%s^FS" % (rows[1]))
		f.write("^FT300,301^BQN,2,8^FH\^FDMA1%s^FS" % (rows[0]))
		f.write("^PQ1,0,1,Y^XZ")
frappe.msgprint(_("Text File created"))
f.close()
download_text()

@frappe.whitelist()
def download_text():
frappe.msgprint(_(“Inside”))
frappe.local.response.filename = “qrcode.txt”
with open(“site1.local/private/files/qrcode.txt”, “r+b”) as fileobj:
filedata = fileobj.read()

frappe.local.response.filecontent = filedata
frappe.local.response.type = "download"	

Now, when I am running this program, the text file is getting created, but I am not able to see any debug commands that I have written. Also, where exactly will this file be downloaded? And, I am not sure if the download_text() file is executing at all.

Is there anything wrong with the code?

Thanks
Uma

There are things to be corrected here.

  • why 2 whitelisted methods?
  • try frappe.logger().debug("Inside") or import pdb; pdb.set_trace() to log / pause for debugging.
  • the code can be generalised and made reusable.
  • If you could generalize feature to print labels and send PR, we can discuss in detail how it can be improved.
1 Like

Hi @revant_one,

Thanks for your response. Sorry, I couldn’t reply to this earlier.

I tried this following code, but it is breaking off during bench migrate. Is there anything wrong with this?

def make_text(args):
	save_path = 'site1.local/private/files'
	file_name = os.path.join(save_path, "qrcode.txt")
	f= open(file_name,"w+")

	f.write("^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA")
	f.write("^PR2,2~SD15^JUS^LRN^CI0^XZ")
	f.write("^XA^MMT^PW812^LL0406^LS0")
	for rows in summ_data:	

##		number_labels = int(number_labels)
		nol = int(number_labels) + 1
		for x in xrange(1, nol):
			f.write("^FT250,79^A0R,28,28^FH\^FD%s^FS" % (rows[0]))
			f.write("^FT533,53^A0R,28,28^FH\^FD%s^FS" % (rows[1]))
			f.write("^FT300,301^BQN,2,8^FH\^FDMA1%s^FS" % (rows[0]))
			f.write("^PQ1,0,1,Y^XZ")
	frappe.msgprint(_("Text File created"))
	f.close()
	frappe.msgprint(_(“Executing the below:”))
	frappe.local.response.filename = "qrcode.txt"
	with open(“site1.local/private/files/qrcode.txt”, “r+b”) as fileobj:
		filedata = fileobj.read()
	frappe.logger().debug("Inside") 
	frappe.local.response.filecontent = filedata
	frappe.local.response.type = "download"

Error on traceback is:

Traceback (most recent call last):
  File "/usr/lib/python2.7/runpy.py", line 174, in _run_module_as_main
    "__main__", fname, loader, pkg_name)
  File "/usr/lib/python2.7/runpy.py", line 72, in _run_code
    exec code in run_globals
  File "/home/uma/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 94, in <module>
    main()
  File "/home/uma/frappe-bench/apps/frappe/frappe/utils/bench_helper.py", line 18, in main
    click.Group(commands=commands)(prog_name='bench')
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 722, in __call__
    return self.main(*args, **kwargs)
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 697, in main
    rv = self.invoke(ctx)
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 1066, in invoke
    return _process_result(sub_ctx.command.invoke(sub_ctx))
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 895, in invoke
    return ctx.invoke(self.callback, **ctx.params)
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/core.py", line 535, in invoke
    return callback(*args, **kwargs)
  File "/home/uma/frappe-bench/env/local/lib/python2.7/site-packages/click/decorators.py", line 17, in new_func
    return f(get_current_context(), *args, **kwargs)
  File "/home/uma/frappe-bench/apps/frappe/frappe/commands/__init__.py", line 24, in _func
    ret = f(frappe._dict(ctx.obj), *args, **kwargs)
  File "/home/uma/frappe-bench/apps/frappe/frappe/commands/site.py", line 226, in migrate
    compileall.compile_dir('../apps', quiet=1)
  File "/usr/lib/python2.7/compileall.py", line 57, in compile_dir
    quiet):
  File "/usr/lib/python2.7/compileall.py", line 57, in compile_dir
    quiet):
  File "/usr/lib/python2.7/compileall.py", line 57, in compile_dir
    quiet):
  File "/usr/lib/python2.7/compileall.py", line 57, in compile_dir
    quiet):
  File "/usr/lib/python2.7/compileall.py", line 57, in compile_dir
    quiet):
  File "/usr/lib/python2.7/compileall.py", line 50, in compile_dir
    if not compile_file(fullname, ddir, force, rx, quiet):
  File "/usr/lib/python2.7/compileall.py", line 99, in compile_file
    ok = py_compile.compile(fullname, None, dfile, True)
  File "/usr/lib/python2.7/py_compile.py", line 115, in compile
    py_exc = PyCompileError(err.__class__, err, dfile or file)
  File "/usr/lib/python2.7/py_compile.py", line 49, in __init__
    errmsg = tbtext.replace('File "<string>"', 'File "%s"' % file)
UnicodeDecodeError: 'ascii' codec can't decode byte 0xe2 in position 151: ordinal not in range(128)

I can’t find where summ_data is defined, assuming it is frappe.get_all()
I can’t find where number_labels is defined?
can you share related code?

Hi @revant_one,

Here is the complete code:

from __future__ import unicode_literals
import frappe
from frappe import _, msgprint
from datetime import datetime, timedelta
from frappe.utils import flt, getdate, datetime,comma_and
from collections import defaultdict
import frappe
import json
import time
import math
import ast
import os.path
import sys
reload(sys)
sys.setdefaultencoding('utf-8')

print sys.getdefaultencoding()

def execute(filters=None):
	global summ_data
	global data
	global number_labels
	summ_data = []
        if not filters: filters = {}

        columns = get_columns()
       
        iwb_map = get_item_map(filters)

        data = []
        
	diff_data = 0	

        for (item_code, serial_number) in sorted(iwb_map):
                qty_dict = iwb_map[item_code, serial_number]
                data.append([
                        serial_number, item_code, qty_dict.warehouse, qty_dict.delivery_required_at, qty_dict.delivery_required_on, qty_dict.vehicle_status, qty_dict.creation
                        
                    ])

	number_labels = filters.get("number_labels")
	for rows in data: 

		created_date = getdate(rows[6])
		created_from = getdate(filters.get("created_from"))
		created_to = getdate(filters.get("created_to"))
	
		if ((created_date >= created_from) and (created_date <= created_to)):
#					
			summ_data.append([rows[0], rows[1],rows[2],
		 	rows[3], rows[4], rows[5], rows[6], number_labels
				
			]) 
						 
	return columns, summ_data 


def get_columns():
        """return columns"""
               
        columns = [
		_("Serial Number")+"::100",
		_("Item Code")+"::100",
		_("Warehouse")+"::100",
		_("Delivery Required At")+"::150",
		_("Delivery Required On")+"::100",
		_("Vehicle Status")+"::100",
		_("Creation Date")+":Date:100",
		_("Number of labels")+"::10"
		
         ]

        return columns

def get_conditions(filters):
        conditions = ""
        if filters.get("created_from"):
		created_date = getdate(filters.get("created_from"))

		conditions += " and sn.creation = '%s'" % frappe.db.escape(filters["created_from"])

	
        return conditions

def get_serial_numbers(filters):
        conditions = get_conditions(filters)
	
        return frappe.db.sql("""select name as serial_number, item_code as item_code, warehouse, delivery_required_at, delivery_required_on, vehicle_status, creation
                from `tabSerial No` sn
                where sn.vehicle_status = "Invoiced but not Received" order by sn.item_code, sn.name""", as_dict=1)


def get_item_map(filters):
        iwb_map = {}
#        from_date = getdate(filters["from_date"])
 #       to_date = getdate(filters["to_date"])
	
        sle = get_serial_numbers(filters)

        for d in sle:
                key = (d.item_code, d.serial_number)
                if key not in iwb_map:
                        iwb_map[key] = frappe._dict({
                                "si_qty": 0.0,
                        })

                qty_dict = iwb_map[(d.item_code, d.serial_number)]

                
                qty_dict.warehouse = d.warehouse
		qty_dict.delivery_required_at = d.delivery_required_at
		qty_dict.delivery_required_on = d.delivery_required_on
		qty_dict.vehicle_status = d.vehicle_status
		qty_dict.creation = d.creation
		
     
        return iwb_map


@frappe.whitelist()
def make_text(args):
	frappe.msgprint(_("Hello"))

	save_path = 'site1.local/private/files'
	file_name = os.path.join(save_path, "qrcode.txt")
	f= open(file_name,"w+")

	f.write("^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA")
	f.write("^PR2,2~SD15^JUS^LRN^CI0^XZ")
	f.write("^XA^MMT^PW812^LL0406^LS0")
	for rows in summ_data:	

##		number_labels = int(number_labels)
		nol = int(number_labels) + 1
		for x in xrange(1, nol):
			f.write("^FT250,79^A0R,28,28^FH\^FD%s^FS" % (rows[0]))
			f.write("^FT533,53^A0R,28,28^FH\^FD%s^FS" % (rows[1]))
			f.write("^FT300,301^BQN,2,8^FH\^FDMA1%s^FS" % (rows[0]))
			f.write("^PQ1,0,1,Y^XZ")
	frappe.msgprint(_("Text File created"))
	f.close()
	frappe.msgprint(_(“Executing the below:”))
	frappe.local.response.filename = "qrcode.txt"
	with open(“site1.local/private/files/qrcode.txt”, “r+b”) as fileobj:
		filedata = fileobj.read()
	frappe.logger().debug("Inside") 
	frappe.local.response.filecontent = filedata
	frappe.local.response.type = "download"

Hi @revant_one,

Hope you are doing fine. I wrote some debug commands inside my code, and am able to get this output in the console. But, my issue is how do I actually download this file onto my system? Is there any command that I am missing out?

My code is:

def download_file():
	print("Inside Download")
	response = Response()
	filename = "qrcode.txt"
	frappe.response.filename = "qrcode.txt"
	response.mimetype = 'text/plain'
	response.charset = 'utf-8'
	with open("proman/public/files/qrcode.txt", "rb") as fileobj:
		filedata = fileobj.read()
	print("Created Filedata")
	frappe.response.filecontent = filedata
	print("Created Filecontent")
	response.type = "download"
	response.headers[b"Content-Disposition"] = ("filename=\"%s\"" % frappe.response['filename'].replace(' ', '_')).encode("utf-8")
	response.data = frappe.response['filecontent']
	print(frappe.response)
	return frappe.response

My console shows:

Inside Download
12:51:22 web.1 | Created Filedata
12:51:22 web.1 | Created Filecontent
12:51:22 web.1 | {‘mimetype’: u’text/plain’, u’docs’: [], ‘charset’: u’utf-8’, ‘filename’: u’qrcode.txt’, ‘filecontent’: ‘^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA^PR2,2~SD15^JUS^LRN^CI0^XZ^XA^MMT^PW812^LL0406^LS0^FT250,79^A0R,28,28^FH\^FDN12345^FS^FT533,53^A0R,28,28^FH\^FDRE0001^FS^FT300,301^BQN,2,8^FH\^FDMA1N12345^FS^PQ1,0,1,Y^XZ^FT250,79^A0R,28,28^FH\^FDN998877^FS^FT533,53^A0R,28,28^FH\^FDRE0001^FS^FT300,301^BQN,2,8^FH\^FDMA1N998877^FS^PQ1,0,1,Y^XZ’, ‘type’: u’download’}

So, how do I download this filecontent on to my system now?

Thanks
Uma

Try removing return frappe.response

Check how download for PDF, CSV work in existing frappe/erpnext code.

Hi Revant,

I tried removing the return frappe.response line also, but it still did not get downloaded.

Now, I tried another method:

	curr_date = utils.today()
	fname = "qrcode"+curr_date+".txt"
	save_path = 'site1.local/private/files'
	file_name = os.path.join(save_path, fname)
	ferp = frappe.new_doc("File")
	ferp.file_name = fname
	ferp.folder = "Home"
	ferp.is_private = 1
	ferp.file_url = "/private/files/"+fname

	f= open(file_name,"w+")

	f.write("^XA~TA000~JSN^LT0^MNW^MTT^PON^PMN^LH0,0^JMA")
	f.write("^PR2,2~SD15^JUS^LRN^CI0^XZ")
	f.write("^XA^MMT^PW812^LL0406^LS0")

	for rows in summ_data:	

##		number_labels = int(number_labels)
		nol = int(number_labels) + 1
		for x in xrange(1, nol):
			f.write("^FT250,79^A0R,28,28^FH\^FD%s^FS" % (rows[0]))
			f.write("^FT533,53^A0R,28,28^FH\^FD%s^FS" % (rows[1]))
			f.write("^FT300,301^BQN,2,8^FH\^FDMA1%s^FS" % (rows[0]))
			f.write("^PQ1,0,1,Y^XZ")

	frappe.msgprint(_("Text File created - Please check File List to download the file"))
	ferp.save()
	f.close()

This is creating the file in the private/files folder, and is also showing under the file list, in ERPNext.

But, when I click on the Download button inside File List, it is showing me the file contents in another page, instead of showing the download dialog box. Is there any other parameter that I need to set?

Thanks
Uma

OK. I found out the issue with this. Its because of the .txt file extension. When I create the same file with .csv extension, I am able to download it. Is there any way to enable txt file download as well?

Thanks
Ima

is there a way to show any file added to server in files folder in erpnxt file manager ? also folder created inside files folder dont show in erpnext file manager ?

You can set a cron job to compare existing file list with files in the DB.

like how if can elaborate ? erpnext file manager fetchs files from /public/files folder in server and private/files folder in server…

i want to manually add a file to server through ftp and then it should show in erpnext filemanager ? how to acheieve this buddy ?

pls help

Depends on your scenario. You know, nearly all files are stored at the root of these folders. Would you like to store them as File doctype? Use sth like frappe.read_file(frappe.get_site_path(“private”, “files”) to start with

i just wanna see files i add to these folder manually or through ftp tp show in erpnext… how to acheive that…

where to write this command ?

Since the user license is free of charge, instead of compromising your erp server folders why don’t you expose the user to the interface where they can upload files?

user downlaod some file on hsi phone n from his phone it gets ftp’ed to server… if user select each file n manually uploads it takes a lot of time

A system level event generator would be nice to trigger Erpnext processes or workflows. Accessing from Erpnext or letting them access Erpnext is not a solution so we need a mediator.