Ejemplo n.º 1
0
def check(request):
    """ Respond to the "/account/check" 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, ["session_key",
                                                          "account_id",
                                                          "update_id"])
        if error != None: return error

        # Get the values we need from the payload.

        session    = request_payload['session']
        account_id = request_payload['fields']['account_id']
        update_id  = request_payload['fields']['update_id']

        if not account_helper.is_valid_account_id(account_id):
            return api_helper.error(request_payload,
                                    api_errors.INVALID_ACCOUNT_ID)

        # Make sure the user is allowed to access the given account.

        if account_id != None:
            if session.user.user_id != account_id.get("user_id"):
                return api_helper.error(request_payload,
                                        api_errors.UNAUTHORIZED)

        # Get the desired account, if it exists.

        account = account_helper.get_account(account_id)

        # See if the account has changed since the client last downloaded it.

        if account != None:
            changed = (account.update_id != update_id)
        else:
            changed = (update_id != 0)

        # Finally, return the response payload back to the caller.

        response_payload = {}
        if changed: response_payload['changed'] = 1
        else:       response_payload['changed'] = 0

        return api_helper.response(request_payload, response_payload)
    except:
        traceback.print_exc()
        return HttpResponseServerError()
Ejemplo n.º 2
0
def enter_transaction(request):
    """ Respond to the "/admin/account/transaction" URL.

        We let the user enter a transaction into the system.
    """
    if request.method == "GET":

        # We're displaying the form for the first time -> set up the default
        # values.

        err_msg                  = None
        type                     = "P"
        user_id                  = ""
        associated_user_id       = ""
        suffix                   = ""
        other_user_id            = ""
        other_associated_user_id = ""
        other_suffix             = ""
        amount                   = ""
        description              = ""

    elif request.method == "POST":

        # Respond to the user submitting our form.

        if request.POST.get("cancel") == "Cancel":
            return HttpResponseRedirect(reverse("tahua.admin_interface." +
                                                "views.main.main"))

        err_msg = None # initially.

        type                     = request.POST['type']
        user_id                  = request.POST['user_id']
        associated_user_id       = request.POST['associated_user_id']
        suffix                   = request.POST['suffix']
        other_user_id            = request.POST['other_user_id']
        other_associated_user_id = request.POST['other_associated_user_id']
        other_suffix             = request.POST['other_suffix']
        amount                   = request.POST['amount']
        description              = request.POST['description']

        account_id = account_helper.make_account_id(user_id,
                                                    associated_user_id,
                                                    suffix)
        if not account_helper.is_valid_account_id(account_id):
            err_msg = "You must enter a valid account identifier."

        if user_id not in ["", None]:
            try:
                user = User.objects.get(user_id=user_id)
            except User.DoesNotExist:
                err_msg = "There is no user with ID " + user_id

        if associated_user_id not in ["", None]:
            try:
                user = User.objects.get(user_id=associated_user_id)
            except User.DoesNotExist:
                err_msg = "There is no user with ID " + associated_user_id

        if err_msg == None:
            try:
                dec_amount = decimal.Decimal(amount)
            except decimal.InvalidOperation:
                err_msg = "Invalid amount."

        if err_msg == None:
            if type not in [Transaction.TYPE_DEPOSIT,
                            Transaction.TYPE_WITHDRAWAL,
                            Transaction.TYPE_PAYMENT,
                            Transaction.TYPE_REVERSAL,
                            Transaction.TYPE_ADJUSTMENT]:
                err_msg = "Please select a valid transaction type."

        if err_msg == None:
            if type == Transaction.TYPE_PAYMENT:
                other_account_id = \
                    account_helper.make_account_id(other_user_id,
                                                   other_associated_user_id,
                                                   other_suffix)
                if not account_helper.is_valid_account_id(other_account_id):
                    err_msg = "You must enter a valid other account identifier."

        # If the entered data was accepted, enter the transaction into the
        # system.

        if err_msg == None:
            account = account_helper.get_or_create_account(account_id)
            if type == Transaction.TYPE_PAYMENT:
                other_account = \
                    account_helper.get_or_create_account(other_account_id)
            else:
                other_account = None

            meta_data = {}
            if description != "":
                meta_data['description'] = description

            if type == Transaction.TYPE_PAYMENT:
                dec_amount = -dec_amount # Deduct amount from source account.

            transaction = Transaction()
            transaction.account       = account
            transaction.other_account = other_account
            transaction.timestamp     = datetime.datetime.now()
            transaction.type          = type
            transaction.amount        = dec_amount
            transaction.metadata      = json.dumps(meta_data)
            transaction.save()

            # If the user is entering a payment, enter the reverse transaction
            # at the same time.

            if type == Transaction.TYPE_PAYMENT:
                transaction = Transaction()
                transaction.account       = other_account
                transaction.other_account = account
                transaction.timestamp     = datetime.datetime.now()
                transaction.type          = type
                transaction.amount        = -dec_amount
                transaction.metadata      = json.dumps(meta_data)
                transaction.save()

            # Finally, tell the user about the entered transaction.

            if type == Transaction.TYPE_PAYMENT:
                msg = utils.formatDecimalAsMoney(-dec_amount) \
                    + " has been transferred from " + account.describe() \
                    + " to " + other_account.describe() + "."
            else:
                msg = 'A transaction of type "' + transaction.type_to_string() \
                    + '" to the value of ' \
                    + utils.formatDecimalAsMoney(dec_amount) \
                    + ' has been entered against the ' \
                    + account.describe()

            return render_to_response("admin_interface/" +
                                      "transaction_entered.html",
                                      {'msg' : msg},
                                      context_instance=RequestContext(request))

    # If we get here, display the form to the user.

    return render_to_response("admin_interface/enter_transaction.html",
                              {'err_msg'                  : err_msg,
                               'type'                     : type,
                               'user_id'                  : user_id,
                               'associated_user_id'       : associated_user_id,
                               'suffix'                   : suffix,
                               'other_user_id'            : other_user_id,
                               'other_associated_user_id' :
                                                       other_associated_user_id,
                               'other_suffix'             : other_suffix,
                               'amount'                   : amount,
                               'description'              : description},
                              context_instance=RequestContext(request))
Ejemplo n.º 3
0
def get(request):
    """ Respond to the "/account/get" 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 are present.

        error = api_helper.check_fields(request_payload,
                                        required_fields=["session_key",
                                                         "account_id"])
        if error != None: return error

        session    = request_payload['session']
        account_id = request_payload['fields']['account_id']

        if not account_helper.is_valid_account_id(account_id):
            return api_helper.error(request_payload,
                                    api_errors.INVALID_ACCOUNT_ID)

        # Make sure the user is allowed to access the given account.

        if account_id != None:
            if session.user.user_id != account_id.get("user_id"):
                return api_helper.error(request_payload,
                                        api_errors.UNAUTHORIZED)

        # Get the desired account, if it exists.

        account = account_helper.get_account(account_id)

        # Build our response payload, based on the account's details.  We start
        # with the account record itself.

        response_payload = {}
        response_payload['account'] = {}

        if account != None:
            response_payload['account']['exists'] = 1
        else:
            response_payload['account']['exists'] = 0

        # Add the account's current balance.

        balance = decimal.Decimal("0.00")
        if account != None:
            transactions = account.transaction_set.all().order_by("timestamp")
            for transaction in transactions:
                balance = balance + transaction.amount
        response_payload['account']['balance'] = balance

        # Add the list of transactions for this account.

        response_payload['account']['transactions'] = []
        if account != None:
            transactions = account.transaction_set.all().order_by("timestamp")

            for transaction in transactions:
                timestamp = transaction.timestamp.isoformat()
                amount    = transaction.amount
                metadata  = transaction.get_metadata()

                transaction_data = {'timestamp' : timestamp,
                                    'amount'    : amount,
                                    'meta_data' : metadata}

                other_account = transaction.other_account
                if other_account != None:
                    other_account_id = account_helper.make_account_id(
                                            other_account.user_id,
                                            other_account.associated_user_id,
                                            other_account.suffix)
                    transaction_data['other_account'] = other_account_id

                response_payload['account']['transactions'].append(
                                                        transaction_data)

        # Add the account's metadata.  Note that we exclude the password and pin
        # number, for security reasons.

        if account != None:
            metadata = account.get_metadata()
        else:
            metadata = {}

        if "password"   in metadata: del metadata['password']
        if "pin_number" in metadata: del metadata['pin_number']

        response_payload['account']['meta_data'] = metadata

        # Add the account's policies, taking into account each policy's default
        # value, the user-specific override (if any), and account-specific
        # override (if any).

        policies = {}
        for policy in Policy.objects.all():
            default = policy.get_default()

            try:
                override = PolicyUserOverride.objects.get(policy=policy,
                                                          user=session.user)
                user_override = override.get_override()
            except PolicyUserOverride.DoesNotExist:
                user_override = None

            if account != None:
                try:
                    override = \
                        PolicyAccountOverride.objects.get(policy=policy,
                                                          account=account)
                    account_override = override.get_override()
                except PolicyAccountOverride.DoesNotExist:
                    account_override = None
            else:
                account_override = None

            if account_override != None:
                value = account_override
            elif user_override != None:
                value = user_override
            else:
                value = default

            policies[policy.name] = value

        response_payload['account']['policies'] = policies

        # Add the account's update ID.

        if account != None:
            response_payload['update_id'] = account.update_id
        else:
            response_payload['update_id'] = 0

        # Finally, return the response payload back to the caller.

        return api_helper.response(request_payload, response_payload)
    except:
        traceback.print_exc()
        return HttpResponseServerError()
Ejemplo n.º 4
0
Archivo: pay.py Proyecto: 3taps/Tahua
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()