Skip to content

Commit

Permalink
Merge pull request #12 from mxmo-co/master
Browse files Browse the repository at this point in the history
Added support for file streams
  • Loading branch information
rmehta committed Mar 17, 2016
2 parents 58dabf3 + 0b6d432 commit 09e122b
Show file tree
Hide file tree
Showing 2 changed files with 198 additions and 0 deletions.
115 changes: 115 additions & 0 deletions example2.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
#-*- coding: utf-8 -*-

from frappeclient import FrappeClient as Client
import os

files = {
'CRM': [
'Customer',
'Address',
'Contact',
'Customer Group',
'Territory',
'Sales Person',
'Terms and Conditions',
'Target Detail',
'Sales Partner',
'Opportunity',
'Lead'
],
'Manufacturing': [
'Production Order',
'Workstation',
'Operation',
'BOM'
],
'Selling': [
'Quotation',
'Sales Order',
'Sales Taxes and Charges',
'Installation Note',
'Product Bundle',
],
'Stock': [
'Purchase Receipt',
'Bin',
'Item',
'Delivery Note',
'Material Request',
'Item Variant',
'Item Attribute Value',
'Serial No',
'Warehouse',
'Stock Entry',
'Price List',
'Item Price',
'Batch',
'Landed Cost Voucher'
],
'Setup': [
'UOM',
'Print Heading',
'Currency Exchange',
'Authorization Rule',
'Authorization Control'
],
'Support': [
'Issue',
'Warranty Claim',
'Maintenance Visit'
],
'HR': [
'Employee',
'Job Applicant',
'Offer Letter',
'Salary Structure',
'Leave Application',
'Expense Claim',
'Expense Claim Type',
'Appraisal',
'Salary Slip',
'Holiday',
'Attendance',
'Leave Type',
'Job Opening',
'Designation',
'Department',
'Earning Type',
'Deduction Type',
'Branch'
]
}

def get_path(*args):
path = os.path.abspath(os.path.join(
os.path.dirname(__file__), 'ERPNext',
*args
))
if not os.path.exists(path):
os.makedirs(path)

return path

def download():
c = Client('http://localhost:8000', 'Administrator', 'admin')

for k,v in files.items():
for dt in v:
for s, ext, method in (('Schemes', 'pdf', 'get_pdf'), ('Upload Templates', 'csv', 'get_upload_template')):
base_path = get_path(k, s)
with open(os.path.join(base_path, '.'.join([dt, ext])), 'wb') as handler:
fn = getattr(c, method)
if ext == 'pdf':
content = fn('DocType', dt, 'Standard')
else:
try:
content = fn(dt)
except Exception, e:
print 'Failed to Download: ' + dt
continue

handler.write(content.getvalue())
print 'Downloaded: `{0}` of {1}'.format(ext, dt)

if __name__ == '__main__':
download()
83 changes: 83 additions & 0 deletions frappeclient/frappeclient.py
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
import requests
import json
from StringIO import StringIO

class AuthError(Exception):
pass

class FrappeException(Exception):
pass

class NotUploadableException(FrappeException):
def __init__(self, doctype):
self.message = "The doctype `{1}` is not uploadable, so you can't download the template".format(doctype)

CAN_DOWNLOAD = []

class FrappeClient(object):
def __init__(self, url, username, password):
self.session = requests.Session()
Expand All @@ -20,21 +27,25 @@ def __exit__(self, *args, **kwargs):
self.logout()

def login(self, username, password):
global CAN_DOWNLOAD
r = self.session.post(self.url, data={
'cmd': 'login',
'usr': username,
'pwd': password
})

if r.json().get('message') == "Logged In":
CAN_DOWNLOAD = []
return r.json()
else:
raise AuthError

def logout(self):
global CAN_DOWNLOAD
self.session.get(self.url, params={
'cmd': 'logout',
})
CAN_DOWNLOAD = []

def insert(self, doc):
res = self.session.post(self.url + "/api/resource/" + doc.get("doctype"),
Expand Down Expand Up @@ -110,6 +121,55 @@ def rename_doc(self, doctype, old_name, new_name):
}
return self.post_request(params)

def get_pdf(self, doctype, name, print_format="Standard", letterhead=True):
params = {
'doctype': doctype,
'name': name,
'format': print_format,
'no_letterhead': int(not bool(letterhead))
}
response = self.session.get(
self.url + "/api/method/frappe.templates.pages.print.download_pdf",
params=params, stream=True)

return self.post_process_file_stream(response)

def get_html(self, doctype, name, print_format="Standard", letterhead=True):
params = {
'doctype': doctype,
'name': name,
'format': print_format,
'no_letterhead': int(not bool(letterhead))
}
response = self.session.get(
self.url + '/print', params=params, stream=True
)
return self.post_process_file_stream(response)

def __load_downloadable_templates(self):
global CAN_DOWNLOAD
CAN_DOWNLOAD = self.get_api('frappe.core.page.data_import_tool.data_import_tool.get_doctypes')

def get_upload_template(self, doctype, with_data=False):
global CAN_DOWNLOAD
if not CAN_DOWNLOAD:
self.__load_downloadable_templates()

if doctype not in CAN_DOWNLOAD:
raise NotUploadableException(doctype)

params = {
'doctype': doctype,
'parent_doctype': doctype,
'with_data': 'Yes' if with_data else 'No',
'all_doctypes': 'Yes'
}

request = self.session.get(self.url +
'/api/method/frappe.core.page.data_import_tool.exporter.get_template',
params=params)
return self.post_process_file_stream(request)

def get_api(self, method, params={}):
res = self.session.get(self.url + "/api/method/" + method + "/",
params=params)
Expand Down Expand Up @@ -153,3 +213,26 @@ def post_process(self, response):
return rjson['data']
else:
return None

def post_process_file_stream(self, response):
if response.ok:
output = StringIO()
for block in response.iter_content(1024):
output.write(block)
return output

else:
try:
rjson = response.json()
except ValueError:
print response.text
raise

if rjson and ("exc" in rjson) and rjson["exc"]:
raise FrappeException(rjson["exc"])
if 'message' in rjson:
return rjson['message']
elif 'data' in rjson:
return rjson['data']
else:
return None

0 comments on commit 09e122b

Please sign in to comment.