My first attempt at writing a Python application to solve a real problem is a one way connector between ERPNext and MYOB AccountRight.
This is the module I have written to connect to the API and get all the tokens. The user fills out a form in ERPNext containing the relevant keys, authorization code, redirect URI etc. which this module reads in and then sends requests for the tokens.
I'm sure it's a terribly primitive approach, but so far I'm happy.
I have a few questions. I seem to find I'm repeating myself quite a bit with the requests, and now that I've also started making other modules that will POST the various documents. I'm wondering if there is some way that I should approach refactoring the requests?
My other question is about the exceptions. I've never used them in a practical setting. Do I have the right idea? Should I be trying to catch the 400 error and inform the user? Are there other request exceptions I should try to catch?
import json
import requests
import frappe
TOKEN_URL = "https://secure.myob.com/oauth2/v1/authorize/"
# Retrieve the API settings saved by the user
client_id = frappe.db.get_single_value('MYOB Settings', 'api_key')
client_secret = frappe.db.get_single_value('MYOB Settings', 'api_secret')
redirect_uri = frappe.db.get_single_value('MYOB Settings', 'redirect_uri')
def get_tokens(doc, method):
# Get the authorization code saved by the user
auth_url = frappe.db.get_single_value('MYOB Settings',
'authorization_url')
# split the authorization code from the url
separator = "code="
try:
auth_code = auth_url.split(separator, 1)[1]
except IndexError as e:
frappe.log_error(frappe.get_traceback(), 'MYOB Authentication '
'Failed')
raise IndexError("Invalid url entered. Check entire url has been paste"
"d.") from e
payload = 'client_id=' + client_id + '&client_secret=' + client_secret +\
'&scope=CompanyFile&grant_type=authorization_code&code='\
+ auth_code + '&redirect_uri=' + redirect_uri
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Authorization': 'Bearer ' + auth_code
}
# Send request for tokens
try:
response = requests.request("POST", TOKEN_URL, headers=headers,
data=payload)
response.raise_for_status()
except Exception as e:
if e.args and e.args[0].startswith("400"):
frappe.msgprint("400 Error: Bad Request. You may have entered "
"incorrect settings")
else:
frappe.msgprint("An unexpected error occurred. Check Error Log.")
frappe.log_error(frappe.get_traceback(), 'MYOB Authentication '
'Failed')
# Save tokens to database
frappe.db.set_value('MYOB Settings',
'MYOB Settings', 'access_token',
response.json()['access_token'])
frappe.db.set_value('MYOB Settings', 'MYOB Settings', 'refresh_token',
response.json()['refresh_token'])
def refresh_tokens(doc, method):
# Get the refresh token from the database
refresh_token = frappe.db.get_single_value('MYOB Settings',
'refresh_token')
payload = 'client_id=' + client_id + '&client_secret=' + client_secret + \
'&grant_type=refresh_token&refresh_token=' + refresh_token
headers = {
'Content-Type': 'application/x-www-form-urlencoded'
}
# Send request for new tokens
try:
response = requests.request("POST", TOKEN_URL, headers=headers,
data=payload)
except Exception as e:
if e.args and e.args[0].startswith("400"):
frappe.msgprint("400 Error: Bad Request. You may have entered "
"incorrect settings")
else:
frappe.msgprint("An unexpected error occurred. Check Error Log.")
frappe.log_error(frappe.get_traceback(), 'MYOB Refreshing Tokens '
'Failed')
# Save tokens to database
frappe.db.set_value('MYOB Settings', 'MYOB Settings', 'access_token',
response.json()['access_token'])
frappe.db.set_value('MYOB Settings', 'MYOB Settings', 'refresh_token',
response.json()['refresh_token'])