diff --git a/src/squarepay/dispense.py b/src/squarepay/dispense.py
index e32393578c39716e0fbff21c9ba9254b37a9caaa..eaa8b2f83f17c3fe00c2c9362f22155580179f02 100644
--- a/src/squarepay/dispense.py
+++ b/src/squarepay/dispense.py
@@ -15,18 +15,23 @@ if DISPENSE_BIN is None:
 	log.warning("DISPENSE_BIN is not defined! Lookups for prices will fallback to weird numbers (for testing)!")
 
 def run_dispense(*args):
+	global DISPENSE_BIN
 	if DISPENSE_BIN is None:
 		return None
 	
 	cmd = (DISPENSE_BIN, ) + args
-	log.info("run_dispense: " + str(cmd))
+	log.debug("run_dispense: " + str(cmd))
 	try:
 		# get a string containing the output of the program
 		res = subprocess.check_output(cmd, timeout=4, universal_newlines=True)
 	except CalledProcessError as e:
 		log.warning("dispense returned error code %d, output: '%s'" % (e.returncode, e.output))
 		return None
-	except TimeoutExpired as e:
+	except FileNotFoundError as e:
+		log.warning("dispense binary not found, make sure DISPENSE_BIN is set correctly")
+		DISPENSE_BIN = None
+		return None
+	except (TimeoutExpired, Exception) as e:
 		log.error(e)
 		return None
 	return res
@@ -36,7 +41,7 @@ def get_item_price(itemid):
 	if (itemid is None or itemid == ""):
 		return None
 	if DISPENSE_BIN is None:
-		return 2223
+		return 1337
 
 	out = run_dispense('iteminfo', itemid)
 	if out is None:
@@ -51,6 +56,10 @@ def get_item_price(itemid):
 		return int(float(s[1]) * 100)
 
 def set_dispense_flag(user, flag, reason):
+	"""
+	updates user flags in dispense, ie. to enable/disable
+	set flag='-disabled' to enable, 'disabled' to disable
+	"""
 	if DISPENSE_BIN is None:
 		log.warning("DISPENSE_BIN is not defined, user will not be disabled")
 		return False
@@ -64,21 +73,46 @@ def set_dispense_flag(user, flag, reason):
 	return True;
 
 def make_dispense_account(user, pin):
+	""" creates dispense account and sets pin """
 	if DISPENSE_BIN is None:
 		log.warning("DISPENSE_BIN is not defined")
 		return False
 
 	cmdargs = [
-		("user","add", user),
-		("acct",user,"+500","treasurer: new user"),
+		("user", "add", user),
+		("acct", user, "+500", "treasurer: new user"),
 		("-u", user, "pinset", pin)
 	]
 
-
 	for args in cmdargs:
-		cmd = [DISPENSE_BIN] + args
-		out = run_dispense('user', 'type', user, flag, reason)
+		out = run_dispense(*args)
 		if out == None:
 			raise CalledProcessError
 
 	return True;
+
+def add_balance(user, amount_cents, reason):
+	""" adds the given amount in cents to a user's dispense account """
+	out = run_dispense('acct', user, str(amount_cents), reason)
+	if out == None:
+		log.warning("failed to add dispense balance to user %s!" % user)
+		return False
+	log.info("added %d cents to account %s" % (amount_cents, user))
+	return True
+
+def purchase_item(item, as_user):
+	""" buys an item as a particular user """
+	out = run_dispense('-u', as_user, item)
+	if out == None:
+		log.warning("could not purchase item %s for user %s" % (item, as_user))
+		return False
+	log.info("purchased item %s on behalf of user %s" % (item, as_user))
+	return True
+
+def give_balance(from_user, to_user, amount_cents, reason):
+	out = run_dispense('-u', from_user, 'give', str(amount_cents), reason)
+	if out == None:
+		log.warning("failed to give balance from %s to %s" % (from_user, to_user))
+		return False
+	log.info("gave %d cents from %s to %s" % (amount_cents, from_user, to_user))
+	return True