Exemple #1
0
    def refund(self, credit_note):
        """Refunds the passed credit note that contained a transfer of
           from another account to the passed account
        """
        if not self.is_logged_in():
            raise PermissionError("You cannot refund a credit note as the "
                                  "user has not yet logged in!")

        if credit_note.account_uid() != self.uid():
            raise ValueError(
                "You cannot refund a transaction from a different "
                "account! %s versus %s" % (credit_note.account_uid(),
                                           self.uid()))

        auth = _Authorisation(resource=self._account_uid, user=self._user)

        args = {"credit_note": credit_note.to_data(),
                "authorisation": auth.to_data()}

        privkey = _PrivateKey()

        result = _call_function(
                    self._accounting_service.service_url(), "refund",
                    args=args,
                    args_key=self._accounting_service.public_key(),
                    response_key=privkey,
                    public_cert=self._accounting_service.public_certificate())

        return result["transaction_record"]
Exemple #2
0
def _get_account_uids(user, accounting_service=None, accounting_url=None):
    """Return the names and UIDs of all of the accounts that belong
        to the passed user on the passed accounting_service
    """
    if accounting_service is None:
        accounting_service = _get_accounting_service(accounting_url)

    elif not accounting_service.is_accounting_service():
        raise ValueError("You can only query account using "
                         "a valid accounting service")

    if not user.is_logged_in():
        raise PermissionError(
            "You can only get information about about a user's accounts "
            "if they have authenticated their login")

    auth = _Authorisation(user=user)
    args = {"authorisation": auth.to_data()}

    privkey = _PrivateKey()

    result = _call_function(
            accounting_service.service_url(), "get_account_uids",
            args=args,
            args_key=accounting_service.public_key(),
            response_key=privkey,
            public_cert=accounting_service.public_certificate())

    return result["account_uids"]
Exemple #3
0
def deposit(user, value, description=None,
            accounting_service=None, accounting_url=None):
    """Tell the system to allow the user to deposit 'value' from
       their (real) financial account to the system accounts
    """
    authorisation = _Authorisation(user=user)

    if accounting_service is None:
        accounting_service = _get_accounting_service(accounting_url)
    else:
        if not accounting_service.is_accounting_service():
            raise TypeError("You can only deposit funds using an "
                            "accounting service!")

    args = {"authorisation": authorisation.to_data()}

    if description is None:
        args["value"] = str(_create_decimal(value))
    else:
        args["transaction"] = _Transaction(value, description).to_data()

    privkey = _PrivateKey()

    result = _call_function(
                    accounting_service.service_url(), "deposit",
                    args=args,
                    args_key=accounting_service.public_key(),
                    response_key=privkey,
                    public_cert=accounting_service.public_certificate())

    return result
Exemple #4
0
    def _refresh(self, force_update=False):
        """Refresh the current status of this account. This fetches
           the latest data, e.g. balance, limits etc. Note that this
           limits you to refreshing at most once every five seconds...
        """
        if self.is_null():
            self._overdraft_limit = _create_decimal(0)
            self._balance = _create_decimal(0)
            self._liability = _create_decimal(0)
            self._receivable = _create_decimal(0)
            self._spent_today = _create_decimal(0)
            return

        if force_update:
            should_refresh = True
        else:
            should_refresh = False

            if self._last_update is None:
                should_refresh = True
            else:
                should_refresh = (_datetime.datetime.now() -
                                  self._last_update).seconds > 5

        if not should_refresh:
            return

        if not self.is_logged_in():
            raise PermissionError(
                "You cannot get information about this account "
                "until after the owner has successfully authenticated.")

        auth = _Authorisation(resource=self._account_uid, user=self._user)

        args = {"authorisation": auth.to_data(),
                "account_name": self.name()}

        privkey = _PrivateKey()

        result = _call_function(
                    self._accounting_service.service_url(), "get_info",
                    args=args,
                    args_key=self._accounting_service.public_key(),
                    response_key=privkey,
                    public_cert=self._accounting_service.public_certificate())

        self._overdraft_limit = _create_decimal(result["overdraft_limit"])
        self._balance = _create_decimal(result["balance"])
        self._liability = _create_decimal(result["liability"])
        self._receivable = _create_decimal(result["receivable"])
        self._spent_today = _create_decimal(result["spent_today"])
        self._description = result["description"]

        self._last_update = _datetime.datetime.now()
Exemple #5
0
def create_account(user, account_name, description=None,
                   accounting_service=None, accounting_url=None):
    """Create an account on the accounting service for the passed
        user, calling the account 'account_name' and optionally
        passing in an account description. Note that the user must
        have authorised the login
    """
    if accounting_service is None:
        accounting_service = _get_accounting_service(accounting_url)

    elif not accounting_service.is_accounting_service():
        raise ValueError("You can only create an account by connecting "
                         "to a valid accounting service")

    if not user.is_logged_in():
        raise PermissionError(
            "You cannot create an account called '%s' for user "
            "'%s' as the user login has not been authenticated." %
            (account_name, user.name()))

    authorisation = _Authorisation(user=user)

    args = {"account_name": str(account_name),
            "authorisation": authorisation.to_data()}

    if description is None:
        args["description"] = "Account '%s' for '%s'" % \
                                (str(account_name), user.name())
    else:
        args["description"] = str(description)

    privkey = _PrivateKey()

    result = _call_function(
                accounting_service.service_url(), "create_account",
                args=args,
                args_key=accounting_service.public_key(),
                response_key=privkey,
                public_cert=accounting_service.public_certificate())

    account_uid = result["account_uid"]

    account = Account()
    account._account_name = account_name
    account._account_uid = account_uid
    account._user = user
    account._accounting_service = accounting_service

    return account
Exemple #6
0
    def perform(self, transaction, credit_account, is_provisional=False):
        """Tell this accounting service to apply the transfer described
           in 'transaction' from this account to the passed account. Note
           that the user must have logged into this account so that they
           have authorised this transaction. This returns the record
           of this transaction
        """
        if not self.is_logged_in():
            raise PermissionError("You cannot transfer value from '%s' to "
                                  "'%s' because you have not authenticated "
                                  "the user who owns this account" %
                                  (str(self), str(credit_account)))

        if not isinstance(transaction, _Transaction):
            raise TypeError("The passed transaction must be of type "
                            "Transaction")

        if not isinstance(credit_account, Account):
            raise TypeError("The passed credit account must be of type "
                            "Account")

        if transaction.is_null():
            return None

        auth = _Authorisation(resource=self._account_uid, user=self._user)

        if is_provisional:
            is_provisional = True
        else:
            is_provisional = False

        args = {"transaction": transaction.to_data(),
                "debit_account_uid": str(self.uid()),
                "credit_account_uid": str(credit_account.uid()),
                "is_provisional": is_provisional,
                "authorisation": auth.to_data()}

        privkey = _PrivateKey()

        result = _call_function(
                    self._accounting_service.service_url(), "perform",
                    args=args,
                    args_key=self._accounting_service.public_key(),
                    response_key=privkey,
                    public_cert=self._accounting_service.public_certificate())

        return result["transaction_records"]
Exemple #7
0
def _get_account_uid(user, account_name, accounting_service=None,
                     accounting_url=None):
    """Return the UID of the account called 'account_name' that
        belongs to passed user on the passed accounting_service
    """
    if account_name is None:
        # return the UID of the default account for this user
        account_name = "main"

    if accounting_service is None:
        accounting_service = _get_accounting_service(accounting_url)

    elif not accounting_service.is_accounting_service():
        raise ValueError("You can only query account using "
                         "a valid accounting service")

    args = {"user_uid": user.uid(),
            "account_name": str(account_name)}

    if user.is_logged_in():
        auth = _Authorisation(user=user)
        args["authorisation"] = auth.to_data()

    privkey = _PrivateKey()

    result = _call_function(
            accounting_service.service_url(), "get_account_uids",
            args=args,
            args_key=accounting_service.public_key(),
            response_key=privkey,
            public_cert=accounting_service.public_certificate())

    account_uids = result["account_uids"]

    for account_uid in account_uids:
        if account_uids[account_uid] == account_name:
            return account_uid

    raise AccountError("There is no account called '%s' for '%s'" %
                       (account_name, str(user)))
    def __init__(self,
                 source=None,
                 destination=None,
                 root=None,
                 ignore_hidden=True,
                 account=None,
                 testing_key=None):
        """Construct the request to write the files specified in 'source'
           to 'destination' in the cloud object store. You can optionally
           pass a 'root' for all of the keys in the object store, and,
           if the source is a directory, you can ignore hidden files using
           'ignore_hidden=True'.

           You must pass the 'account' from which payment will be taken to
           write files to the object store.

            Args:
                source (str): source directory to traverse
                destination (str, optional): destination directory
                root (str): root key to use in object store
                ignore_hidden (bool): If True ignore hidden files in folders,
                else include hidden files
                account (Account): instance of Account class
                testing_key (str): passed to enable testing of class
            Returns:
                None

        """
        super().__init__()

        (filenames, keys) = FileWriteRequest.expand_source_and_destination(
            source, destination, root, ignore_hidden)

        self._destination_keys = keys
        self._source_filenames = filenames
        self._file_sizes = []
        self._checksums = []

        if len(self._source_filenames) == 0:
            self._uid = None
            return

        for filename in self._source_filenames:
            (size, checksum) = _get_filesize_and_checksum(filename)
            self._file_sizes.append(size)
            self._checksums.append(checksum)

        self._is_testing = False

        if testing_key:
            self._is_testing = True
            self._testing_key = testing_key
        elif account is not None:
            from Acquire.Client import Account as _Account
            if not isinstance(account, _Account):
                raise TypeError("The passed account must be type Account")

            if not account.is_logged_in():
                raise PermissionError(
                    "You can only authorise payment from the account if you "
                    "have logged in")

        else:
            raise ValueError("You must pass a valid account to write files!")

        self._uid = str(_uuid4())

        from Acquire.Identity import Authorisation as _Authorisation

        if self._is_testing:
            self._account_uid = "something"
            self._accounting_service_url = "somewhere"
            self._authorisation = _Authorisation(resource=self.resource_key(),
                                                 testing_key=self._testing_key)

        else:
            self._account_uid = account.uid()
            self._accounting_service_url = account.accounting_service() \
                                                  .canonical_url()

            self._authorisation = _Authorisation(resource=self.resource_key(),
                                                 user=account.owner())
Exemple #9
0
    def write(account=None, resource=None,
              recipient_url=None, max_spend=None,
              expiry_date=None):
        """Create and return a cheque that can be used at any point
           in the future to authorise a transaction. If 'recipient_url'
           is supplied, then only the service with the matching
           URL can 'cash' the cheque (it will need to sign the cheque
           before sending it to the accounting service). If 'max_spend'
           is specified, then the cheque is only valid up to that
           maximum spend. Otherwise, it is valid up to the maximum
           daily spend limit (or other limits) of the account. If
           'expiry_date' is supplied then this cheque is valid only
           before the supplied datetime. If 'resource' is
           supplied then this cheque is only valid to pay for the
           specified resource (this should be a string that everyone
           agrees represents the resource in question). Note that
           this cheque is for a future transaction. We do not check
           to see if there are sufficient funds now, and this does
           not affect the account. If there are insufficient funds
           when the cheque is cashed (or it breaks spending limits)
           then the cheque will bounce.

           Args:
                account (Account, default=None): Account to use to write
                cheque
                resource (str, default=None): Define the resource to pay for
                recipient_url (str, default=None): URL of service to use
                max_spend (Decimal, default=None): Limit of cheque
                expiry_date (datetime, default=None): Cheque's expiry date
        """

        from Acquire.Client import Account as _Account

        if not isinstance(account, _Account):
            raise TypeError("You must pass a valid Acquire.Client.Account "
                            "object to write a cheque...")

        if max_spend is not None:
            from Acquire.ObjectStore import decimal_to_string \
                as _decimal_to_string
            max_spend = _decimal_to_string(max_spend)

        if expiry_date is not None:
            from Acquire.ObjectStore import datetime_to_string \
                as _datetime_to_string
            expiry_date = _datetime_to_string(expiry_date)

        if recipient_url is not None:
            recipient_url = str(recipient_url)

        from Acquire.ObjectStore import create_uuid as _create_uuid
        from Acquire.Identity import Authorisation as _Authorisation

        info = _json.dumps({"recipient_url": recipient_url,
                            "max_spend": max_spend,
                            "expiry_date": expiry_date,
                            "uid": _create_uuid(),
                            "resource": str(resource),
                            "account_uid": account.uid()})

        auth = _Authorisation(user=account.user(), resource=info)

        data = {"info": info, "authorisation": auth.to_data()}

        cheque = Cheque()

        cheque._cheque = account.accounting_service().encrypt_data(data)
        cheque._accounting_service_url = \
            account.accounting_service().canonical_url()

        return cheque