def test_pay_to_alias(self): """ Test the logic of making a payment to an alias. """ # Create a source account and give it some funds. src_user = self.create_random_user() src_account = Account() src_account.user_id = src_user.user_id src_account.suffix = "source account" src_account.save() transaction = Transaction() transaction.account = src_account transaction.timestamp = datetime.datetime.now() transaction.type = Transaction.TYPE_DEPOSIT transaction.amount = decimal.Decimal("100.00") transaction.save() # Create a user to make a payment to, and set up an alias for that # user. Note that we store the user ID and alias in global variables, # so our testing alias resolver can resolve the alias. dst_user = self.create_random_user() global _test_alias_id, _test_user_id _test_user_id = dst_user.user_id _test_alias_id = utils.random_letters() # Open a session as the source user, so we can make a payment from that # account. err_msg = self.open_session(src_user.user_id, src_user.password) self.assertEqual(err_msg, None) # Define our source and destination accounts, using the alias for the # destination account. src_account_id = {'user_id' : src_user.user_id, 'suffix' : "source account"} dst_account_id = {'user_alias' : _test_alias_id} # Make a payment from the source to the destination account. resolver_path = "tahua.tests.test_payments.test_alias_resolver" with self.settings(TAHUA_USER_ALIAS_RESOLVER=resolver_path): success,response = self.call_api("tahua.api.pay.pay", include_session_key=True, from_account_id=src_account_id, to_account_id=dst_account_id, amount="10.00", pin_number=src_user.pin_number, meta_data={}) if not success: self.fail(response) # Finally, check that the payment went to the right account. account_id = {'user_id' : dst_user.user_id} balance = account_helper.get_account_balance(account_id) self.assertEqual(balance, decimal.Decimal("10.00"))
def pay(request): """ Respond to the "/pay" API call. """ try: # Extract our payload from the request parameters. request_payload = api_helper.process_request(request) if "error" in request_payload: return request_payload["error"] # Check that the required fields have all been supplied. error = api_helper.check_fields( request_payload, required_fields=["session_key", "from_account_id", "to_account_id", "amount"], optional_fields=["pin_number", "meta_data"], ) if error != None: return error # Get the values we need from the payload. session = request_payload["session"] from_account_id = request_payload["fields"]["from_account_id"] to_account_id = request_payload["fields"]["to_account_id"] amount = decimal.Decimal(request_payload["fields"]["amount"]) pin_number = request_payload["fields"].get("pin_number") meta_data = request_payload["fields"].get("meta_data") # If the "to" account refers to a user alias, call the user alias # resolver to translate from the user alias to the underlying user ID. if isinstance(to_account_id, dict): if "user_alias" in to_account_id: user_id = alias_resolver.resolve(to_account_id["user_alias"]) if user_id == None: return api_helper.error(request_payload, api_errors.UNKNOWN_ACCOUNT_ALIAS) to_account_id["user_id"] = user_id del to_account_id["user_alias"] # Check that the "from" and "to" accounts are both valid. if not account_helper.is_valid_account_id(from_account_id): return api_helper.error(request_payload, api_errors.INVALID_ACCOUNT_ID) if not account_helper.is_valid_account_id(to_account_id): return api_helper.error(request_payload, api_errors.INVALID_ACCOUNT_ID) # Make sure the user is allowed to access the "from" account. if session.user.user_id != from_account_id.get("user_id"): return api_helper.error(request_payload, api_errors.UNAUTHORIZED) # If this transaction requires a PIN number, ensure that the correct # PIN has been supplied. max_payment_without_pin = account_helper.get_account_policy(from_account_id, "max_payment_without_pin") if max_payment_without_pin != None: if amount >= max_payment_without_pin: # We need a PIN number for this payment -> check that the # correct PIN has been supplied. if pin_number == None: return api_helper.error(request_payload, api_errors.PIN_NUMBER_REQUIRED) if pin_number != session.user.pin_number: return api_helper.error(request_payload, api_errors.INVALID_PIN_NUMBER) # Check that the amount isn't too high, or doesn't exceed the daily # transaction limit...eventually. # Check that the account has enough funds to cover the desired # transaction. min_account_balance = account_helper.get_account_policy(from_account_id, "min_account_balance") if min_account_balance == None: min_account_balance = decimal.Decimal("0.00") account_balance = account_helper.get_account_balance(from_account_id) if account_balance - amount < min_account_balance: return api_helper.error(request_payload, api_errors.INSUFFICIENT_FUNDS) # If necessary, create the Account record(s) for the from and to # accounts. from_account = account_helper.get_or_create_account(from_account_id) to_account = account_helper.get_or_create_account(to_account_id) # If we get here, we're ready to make this payment. Create appropriate # Transaction records to transfer the funds from one account to the # other. timestamp = datetime.datetime.now() transaction = Transaction() transaction.account = from_account transaction.other_account = to_account transaction.timestamp = timestamp transaction.type = Transaction.TYPE_PAYMENT transaction.amount = -amount transaction.set_metadata(meta_data) transaction.save() transaction = Transaction() transaction.account = to_account transaction.other_account = from_account transaction.timestamp = timestamp transaction.type = Transaction.TYPE_PAYMENT transaction.amount = amount transaction.set_metadata(meta_data) transaction.save() # Update the 'update_id' values for both accounts, so that the various # clients will know that the accounts have been updated. account_helper.increment_update_id(from_account.id) account_helper.increment_update_id(to_account.id) # Finally, return an empty response payload back to the caller. We # return an empty response (as opposed to an error response) when the # payment was successful. response_payload = {} return api_helper.response(request_payload, response_payload) except: traceback.print_exc() return HttpResponseServerError()