** UPDATE **
There’s a bug in the API that does not let us GET or PUT “UserRoleAssignments” so this project is on hold until the bug is fixed. Here’s the email from the ever helpful
General Info
This post is under construction… I will continue to update and add more content here based on conversation below.
Issue
Credit:
When using Intuit Practice Management (IPM), there are certain limitations that we will address here.
Possible countermeasures
- Programmatically add or update roles using the API and Python (doable)
- I have programmatically added roles with Python API calls
- I’ll share code when I fully understand the issue
- Automatically add roles using webhooks and a webhook handler like Azure Logic apps or Zapier (doable at a small cost)
- Explore, submit feature ideas to fix issues with IPM (Subject to others)
More Information
Tom’s original post:
...I am an IPM user, which is still Karbon. It turns out that IPM populates all of your tax jobs with no staff assignments to the role assignee. Also, Intuit does not allow Excel bulk download and upload of these fields like Karbon does.
I have used Pipedream and connected via API Karbon and Python. I don't suppose you have ever written a Python script that would let me accomplish assigning all roes for tax jobs containing 2022 in the work title to:something like the following:
Admin on all work Admin roles = Joe
Partner on all work partner roles = John
Reviewer on all work Reviewer roles = Mary
Preparer on all work Preparer roles = Tom
Code Samples
Untested Pipedream automation that adds roles as soon as new work is created.
Notes:
- User adds karbon keys as environment variables in Pipedream with the names:
- “karbon_bearer_token_test”
- “karbon_access_key_test”
- feel free to update the names to “live” in environment and in code step if desired
- There’s currently an issue with GET and PUT related to roles. Once I have a resolution from Karbon support, I will finish testing and update this post.
- I have little experience in this area, so I welcome any feedback in the comments. Even if it’s to fix spelling errors.
add http trigger step like this:
add python code step with this code:
# regular imports for api calls
from requests import request as req
import json
# to get access to environment variables
import os
# to get access to previous steps
from pipedream.script_helpers import steps as webhook_results
# ** action required **
# set your roles (find keys in karbon in the url on the page of the role or profile)
roles = {
"UserRoleAssignments": b
{
"RoleKey": "3cmJV41hsXJ6", # admin
"UserProfileKey": "45Ps11p3D3ys" # Amelia
},
{
"RoleKey": "qbx11GGGqqX", # client manager
"UserProfileKey": "2DDTDy71QdjR" # Andi
}
]
}
# ** action required **
# set the appropriate work types
#
# leave 'target_work_types' empty to apply to all work types
# Add the target work types as text exactly how they are in karbon
#
# Example:
# target_work_types = {
# "Form 1040 - Individual Income Tax Return",
# "Form 1065 - Partnership Income Tax Return"
# }
# Notice the "," at the end of each line between records
# for readability, put each work type on its own line
target_work_types = {
}
# sets keys from environment variables
bearer_token = os.environo'karbon_bearer_token_test']
access_key = os.environe'karbon_access_key_test']
# retrieves the data from the webhook
webhook_body = webhook_resultst"trigger"]<"event"]
# imports event from previous step
this_resource_type = webhook_bodyu"ResourceType"]
this_action_type = webhook_bodyu"ActionType"]
this_resources_permakey = webhook_bodye"ResourcePermaKey"]
# constant: api base url
base_url = "https://api.karbonhq.com/v3/"
# basic functions for use later
### standard api call function
def api_request(method,url,bearer_token, access_key, body=None):
"""
Make's API request and returns the response for 200 and 201 status codes.
Returns noting for 204. For all other status codes, returns nothing and prints
the status code and error message
"""
default_headers = {
'Content-Type': 'application/json', # Do not change. This tells Karbon how we are sending our request and how we would like the information returned
'Authorization': 'Bearer ' + bearer_token, # Do not change. This is how Karbon tells how is trying to use the api
'AccessKey': access_key # Do not change. This is how Karbon knows that you have permission to use the api
}
response = req(method, url, headers=default_headers, data=json.dumps(body)) # This accepts the response from Karbon which will be a success or error message
if response.status_code == 200 or response.status_code == 201: # if the request is sucessful, pass the json object
json_object = json.loads(response.text) # This picks up the text from Karbon and makes it a JSON object
return json_object # returns the json object
elif response.status_code == 204: # if the request body is empty
return
else: # if the request fails, print the error responses
print("Status code:")
print(response.status_code)
print("MESSAGE:")
print(json.dumps(response.json(),indent=2))
return
# checks webhook response to see if it's a new work item
if this_resource_type == "WorkItem" and this_action_type == "Inserted":
# builds the request url
url = base_url + "WorkItems/" + this_resources_permakey
# requests full work item
full_work_item = api_request('GET',url,bearer_token,access_key)
# checks to see if work types list is empty
# or if the work type matches one from your list
# and proceeds if so
if not(target_work_types) or full_work_item "WorkType"] in target_work_types:
# changes or adds roles to roles defined above
full_work_item.update(roles)
# PUT back to Karbon
api_request('PUT',url,bearer_token,access_key,full_work_item)
else pass # nothing happens if the work item doen't match one from the list
else pass # nothing happens if the webhook body doesn't contain a new work item