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"]
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"]
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
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()
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
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"]
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())
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