コード例 #1
0
ファイル: _account.py プロジェクト: samle-appsbroker/acquire
    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...

           Args:
                force_update (bool, default=False): Force the refresh
           Returns:
                None
        """
        if self.is_null():
            from Acquire.Accounting import create_decimal as _create_decimal
            from Acquire.Accounting import Balance as _Balance
            self._overdraft_limit = _create_decimal(0)
            self._balance = _Balance()
            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.")

        from Acquire.Client import Authorisation as _Authorisation
        from Acquire.Accounting import create_decimal as _create_decimal

        service = self.accounting_service()

        auth = _Authorisation(resource="get_info %s" % self._account_uid,
                              user=self._user)

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

        result = service.call_function(function="get_info", args=args)

        from Acquire.Accounting import Balance as _Balance
        self._balance = _Balance.from_data(result["balance"])
        self._overdraft_limit = _create_decimal(result["overdraft_limit"])
        self._description = result["description"]

        self._last_update = _datetime.datetime.now()
コード例 #2
0
    def split(value, description):
        """Split the passed transaction described by 'description' with value
           'value' into a list of transactions that fit the maximum transaction
           limit.

           Args:
                value (float): Value to split between transactions
                description (str): Description of transactions
           Returns:
                list: List of Transactions
        """
        value = _create_decimal(value)

        if value < Transaction.maximum_transaction_value():
            t = Transaction(value, description)
            return [t]
        else:
            orig_value = value
            values = []

            while value > Transaction.maximum_transaction_value():
                values.append(Transaction.maximum_transaction_value())
                value -= Transaction.maximum_transaction_value()

            if value > 0:
                values.append(value)

            total = 0
            for value in values:
                total += value

            if total != orig_value:
                values[-1] -= (total - orig_value)

            transactions = []

            for i in range(0, len(values)):
                transactions.append(
                    Transaction(
                        values[i],
                        "%s: %d of %d" % (description, i + 1, len(values))))

            values = None

            total = 0
            for transaction in transactions:
                total += transaction.value()

            # ensure that the total is also rounded to 6 dp
            total = _create_decimal(total)

            if total != orig_value:
                from Acquire.Accounting import TransactionError
                raise TransactionError(
                    "Error as split sum (%s) is not equal to the original "
                    "value (%s)" % (total, orig_value))

            return transactions
コード例 #3
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()
コード例 #4
0
    def __init__(self, key=None):
        """Construct, optionally from the passed key"""
        if key is not None:
            t = TransactionInfo.from_key(key)

            import copy as _copy
            self.__dict__ = _copy.copy(t.__dict__)
        else:
            from Acquire.Accounting import create_decimal as _create_decimal
            self._value = _create_decimal(0)
            self._receipted_value = _create_decimal(0)
            self._code = None
            self._datetime = None
            self._uid = None
コード例 #5
0
    def receipt(self, credit_note, receipted_value=None):
        """Receipt the passed credit note that contains a request to
           transfer value from another account to the passed account
        """
        if not self.is_logged_in():
            raise PermissionError("You cannot receipt a credit note as the "
                                  "user has not yet logged in!")

        if credit_note.account_uid() != self.uid():
            raise ValueError(
                "You cannot receipt 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()}

        if receipted_value is not None:
            args["receipted_value"] = str(_create_decimal(receipted_value))

        privkey = _PrivateKey()

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

        return result["transaction_record"]
コード例 #6
0
    def from_data(data):
        """Construct and return a new CreditNote from the passed json-decoded
            dictionary

            Args:
                data (dict): JSON serialised dictionary of object
            Returns:
                CreditNote: CreditNote created from JSON data
        """
        note = CreditNote()

        if (data and len(data) > 0):
            from Acquire.ObjectStore import string_to_datetime \
                as _string_to_datetime
            from Acquire.Accounting import create_decimal as _create_decimal

            note._account_uid = data["account_uid"]
            note._debit_account_uid = data["debit_account_uid"]
            note._uid = data["uid"]
            note._debit_note_uid = data["debit_note_uid"]
            note._datetime = _string_to_datetime(data["datetime"])
            note._value = _create_decimal(data["value"])
            note._is_provisional = data["is_provisional"]

            if note._is_provisional:
                note._receipt_by = _string_to_datetime(data["receipt_by"])

        return note
コード例 #7
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
コード例 #8
0
ファイル: _receipt.py プロジェクト: samle-appsbroker/acquire
    def __init__(self,
                 credit_note=None,
                 authorisation=None,
                 receipted_value=None):
        """Create a receipt for the transaction that resulted in the passed
           credit note. Specify the authorisation of the receipt, and
           optionally specify the actual receipted value (which may be
           less than the value in the passed credit note)
        """
        if credit_note is None:
            self._credit_note = None
            self._authorisation = None
            from Acquire.Accounting import create_decimal as _create_decimal
            self._receipted_value = _create_decimal(0)
            return

        from Acquire.Accounting import CreditNote as _CreditNote
        from Acquire.Identity import Authorisation as _Authorisation

        if not isinstance(credit_note, _CreditNote):
            raise TypeError("The credit note must be of type CreditNote")

        if not isinstance(authorisation, _Authorisation):
            raise TypeError("The authorisation must be of type Authorisation")

        if not credit_note.is_provisional():
            raise ValueError("You cannot receipt a transaction that was "
                             "not provisional! - %s" % str(credit_note))

        if receipted_value is not None:
            from Acquire.Accounting import create_decimal as _create_decimal
            receipted_value = _create_decimal(receipted_value)

            if receipted_value < 0:
                raise ValueError("You cannot receipt a value that is less "
                                 "than zero! %s" % receipted_value)
            elif receipted_value > credit_note.value():
                raise ValueError("You cannot receipt a value that is greater "
                                 "than the value of the original credit "
                                 "note - %s versus %s" %
                                 (receipted_value, credit_note.value()))
        else:
            receipted_value = credit_note.value()

        self._credit_note = credit_note
        self._authorisation = authorisation
        self._receipted_value = receipted_value
コード例 #9
0
    def maximum_transaction_value():
        """Return the maximum value for a single transaction. Currently this
           is 999999.999999 so that a transaction fits into a f013.6 string

           Returns:
                Decimal: Maximum transaction value
        """
        return _create_decimal(999999.999999)
コード例 #10
0
ファイル: _balance.py プロジェクト: samle-appsbroker/acquire
 def available(self, overdraft_limit=None):
     """Return the available balance (balance - liability)"""
     if overdraft_limit is None:
         return self.balance() - self.liability()
     else:
         from Acquire.Accounting import create_decimal as _create_decimal
         overdraft_limit = _create_decimal(overdraft_limit)
         return self.balance() - self.liability() + overdraft_limit
コード例 #11
0
ファイル: _balance.py プロジェクト: samle-appsbroker/acquire
    def total(balances):
        """Return the sum of the passed balances"""
        from Acquire.Accounting import create_decimal as _create_decimal
        balance = _create_decimal(0)
        liability = _create_decimal(0)
        receivable = _create_decimal(0)

        for b in balances:
            if type(b) is not Balance:
                raise TypeError("You can only sum Balance objects!")

            balance += b._balance
            liability += b._liability
            receivable += b._receivable

        return Balance(balance=balance,
                       liability=liability,
                       receivable=receivable,
                       _is_safe=True)
コード例 #12
0
ファイル: _refund.py プロジェクト: samle-appsbroker/acquire
    def value(self):
        """Return the value of the refund

           Decimal: Value of this refund
        """
        if self.is_null():
            from Acquire.Accounting import create_decimal as _create_decimal
            return _create_decimal(0)
        else:
            return self._credit_note.value()
コード例 #13
0
    def round(value):
        """Round the passed floating point value to the precision
           level of the transaction (currently 6 decimal places)

           Args:
                value (float): Value to convert to Decimal
           Returns:
                Decimal: Rounded value
        """
        return _create_decimal(value)
コード例 #14
0
def string_to_decimal(s, default=0):
    """Return the decimal that had been encoded via 'decimal_to_string'.
       This string must have been created via 'decimal_to_string'

       Args:
            s (str): String to convert to Decimal
       Returns:
            Decimal: Decimal version of string
    """
    from Acquire.Accounting import create_decimal as _create_decimal
    return _create_decimal(s, default=default)
コード例 #15
0
ファイル: _receipt.py プロジェクト: samle-appsbroker/acquire
    def value(self):
        """Return the original (provisional) value of the transaction

           Returns:
                Decimal: Value of this receipt
        """
        if self.is_null():
            from Acquire.Accounting import create_decimal as _create_decimal
            return _create_decimal(0)
        else:
            return self._credit_note.value()
コード例 #16
0
ファイル: _receipt.py プロジェクト: samle-appsbroker/acquire
    def receipted_value(self):
        """Return the receipted value. This is guaranteed to be less than
           or equal to the provisional value in the attached CreditNote

           Returns:
                Decimal: Receipted value
        """
        if self.is_null():
            from Acquire.Accounting import create_decimal as _create_decimal
            return _create_decimal(0)
        else:
            return self._receipted_value
コード例 #17
0
ファイル: _balance.py プロジェクト: samle-appsbroker/acquire
    def __add__(self, other):
        """Add balances together"""
        if type(other) is Balance:
            return Balance(balance=self._balance + other._balance,
                           liability=self._liability + other._liability,
                           receivable=self._receivable + other._receivable,
                           _is_safe=True)

        from Acquire.Accounting import TransactionInfo as _TransactionInfo
        if type(other) is _TransactionInfo:
            balance = self._balance
            liability = self._liability
            receivable = self._receivable

            if other.is_credit():
                balance += other.value()
            elif other.is_debit():
                balance -= other.value()
            elif other.is_liability():
                liability += other.value()
            elif other.is_accounts_receivable():
                receivable += other.value()
            elif other.is_received_receipt():
                balance -= other.receipted_value()
                liability -= other.original_value()
            elif other.is_sent_receipt():
                balance += other.receipted_value()
                receivable -= other.original_value()
            elif other.is_received_refund():
                balance += other.value()
            elif other.is_sent_refund():
                balance -= other.value()

            return Balance(balance=balance,
                           liability=liability,
                           receivable=receivable,
                           _is_safe=True)

        from Acquire.Accounting import Transaction as _Transaction
        if type(other) is _Transaction:
            return Balance(balance=self._balance + other.value(),
                           liability=self._liability,
                           receivable=self._receivable,
                           _is_safe=True)

        from Acquire.Accounting import create_decimal as _create_decimal
        value = _create_decimal(other)
        return Balance(balance=self._balance + value,
                       liability=self._liability,
                       receivable=self._receivable,
                       _is_safe=True)
コード例 #18
0
    def from_data(data):
        """Return a newly constructed transaction from the passed dictionary
           that has been decoded from JSON

           Args:
                data (dict): Dictionary from JSON
           Returns:
                Transaction: Object created from JSON
        """
        transaction = Transaction()

        if (data and len(data) > 0):
            from Acquire.Accounting import create_decimal as _create_decimal
            transaction._value = _create_decimal(data["value"])
            transaction._description = data["description"]

        return transaction
コード例 #19
0
    def __init__(self, value=0, description=None):
        """Create a transaction with the passed value and description. Values
           are positive values with a minimum resolution of 1e-6 (6 decimal
           places) and cannot exceed 999999.999999 (i.e. cannot be 1 million
           or greater). This is to ensure that a value will always fit into a
           f13.6 string (which is used for keys). If you need larger
           transactions, then use the static 'split' function to break
           a single too-large transaction into a list of smaller
           transactions
        """
        value = _create_decimal(value)

        if value > Transaction.maximum_transaction_value():
            from Acquire.Accounting import TransactionError
            raise TransactionError(
                "You cannot create a transaction (%s) with a "
                "value greater than %s. Please "
                "use 'split' to break this transaction (%s) into "
                "several separate transactions" %
                (description, Transaction.maximum_transaction_value(), value))

        # ensure that the value is limited in resolution to 6 decimal places
        self._value = value

        if self._value < 0:
            from Acquire.Accounting import TransactionError
            raise TransactionError(
                "You cannot create a transaction (%s) with a "
                "negative value! %s" % (description, value))

        if description is None:
            if self._value > 0:
                from Acquire.Accounting import TransactionError
                raise TransactionError(
                    "You must give a description to all non-zero "
                    "transactions! %s" % self.value())
            else:
                self._description = None
        else:
            # ensure we are using utf-8 encoded strings
            self._description = str(description).encode("utf-8") \
                                                .decode("utf-8")
コード例 #20
0
ファイル: _receipt.py プロジェクト: samle-appsbroker/acquire
    def from_data(data):
        """Return a Receipt from the passed JSON-decoded dictionary

           Args:
                data (dict): JSON dictionary to create object
           Returns:
                Receipt: Receipt created from JSON

        """
        r = Receipt()

        if (data and len(data) > 0):
            from Acquire.Accounting import CreditNote as _CreditNote
            from Acquire.Accounting import create_decimal as _create_decimal
            from Acquire.Identity import Authorisation as _Authorisation
            r._credit_note = _CreditNote.from_data(data["credit_note"])
            r._authorisation = _Authorisation.from_data(data["authorisation"])
            r._receipted_value = _create_decimal(data["receipted_value"])

        return r
コード例 #21
0
ファイル: _balance.py プロジェクト: samle-appsbroker/acquire
    def __sub__(self, other):
        """Add balances together"""
        if type(other) is type(Balance):
            return Balance(balance=self._balance - other._balance,
                           liability=self._liability - other._liability,
                           receivable=self._receivable - other._receivable,
                           _is_safe=True)

        from Acquire.Accounting import Transaction as _Transaction
        if type(other) is _Transaction:
            return Balance(balance=self._balance - other.value(),
                           liability=self._liability,
                           receivable=self._receivable,
                           _is_safe=True)

        from Acquire.Accounting import create_decimal as _create_decimal
        value = _create_decimal(other)
        return Balance(balance=self._balance + value,
                       liability=self._liability,
                       receivable=self._receivable,
                       _is_safe=True)
コード例 #22
0
ファイル: _account.py プロジェクト: samle-appsbroker/acquire
    def receipt(self, credit_note, receipted_value=None):
        """Receipt the passed credit note that contains a request to
           transfer value from another account to the passed account

           Args:
                credit_note (CreditNote): CreditNote to use to create
                receipt
                receipted_value (Decimal, default=None): Receipted value
            Returns:
                TransactionRecord: Record of this transaction
        """
        if not self.is_logged_in():
            raise PermissionError("You cannot receipt a credit note as the "
                                  "user has not yet logged in!")

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

        from Acquire.Client import Authorisation as _Authorisation
        from Acquire.Accounting import create_decimal as _create_decimal

        service = self.accounting_service()

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

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

        if receipted_value is not None:
            args["receipted_value"] = str(_create_decimal(receipted_value))

        result = service.call_function(function="receipt", args=args)

        return result["transaction_record"]
コード例 #23
0
    def __init__(self,
                 debit_note=None,
                 account=None,
                 receipt=None,
                 refund=None,
                 bucket=None):
        """Create the corresponding credit note for the passed debit_note. This
           will credit value from the note to the passed account. The credit
           will use the same UID as the debit, and the same datetime. This
           will then be paired with the debit note to form a TransactionRecord
           that can be written to the ledger
        """
        self._account_uid = None

        nargs = (receipt is not None) + (refund is not None)

        if nargs > 1:
            raise ValueError("You can create a CreditNote with a receipt "
                             "or a refund - not both!")

        if receipt is not None:
            self._create_from_receipt(debit_note, receipt, account, bucket)

        elif refund is not None:
            self._create_from_refund(debit_note, refund, account, bucket)

        elif (debit_note is not None) and (account is not None):
            self._create_from_debit_note(debit_note, account, bucket)

        else:
            self._debit_account_uid = None
            self._datetime = None
            self._uid = None
            self._debit_note_uid = None

            from Acquire.Accounting import create_decimal as _create_decimal
            self._value = _create_decimal(0)
コード例 #24
0
 def __eq__(self, other):
     if isinstance(other, Transaction):
         return self.value() == other.value() and \
                self.description() == other.description()
     else:
         return self.value() == _create_decimal(other)
コード例 #25
0
 def __gt__(self, other):
     if isinstance(other, Transaction):
         return self.value() > other.value()
     else:
         return self.value() > _create_decimal(other)
コード例 #26
0
ファイル: _receipt.py プロジェクト: samle-appsbroker/acquire
    def create(credit_notes, authorisation, receipted_value=None):
        """Construct a series of receipts from the passed credit notes,
           each of which is authorised using the passed authorisation.
           If 'receipted_value' is specified, then the sum total of
           receipts will equal 'receipted_value'. This cannot be
           greater than the sum of the passed credit notes. If it
           is less then the value, then the difference is subtracted
           from the first receipts returned

           Args:
             credit_notes (list): List of credit notes to receipt
             autorisation (Authorisation): Authorisation for credit notes
             receipted_value (Decimal, default=None): Total value to receipt

            Returns:
                Receipt or list[Receipt]: If <= 1 credit note Receipt, else
                list of Receipts

        """
        try:
            credit_note = credit_notes[0]
        except:
            return Receipt(credit_notes, authorisation, receipted_value)

        if len(credit_notes) == 0:
            return Receipt()
        elif len(credit_notes) == 1:
            return Receipt(credit_notes[0], authorisation, receipted_value)

        from Acquire.Accounting import create_decimal as _create_decimal
        total_value = _create_decimal(0)

        from Acquire.Accounting import CreditNote as _CreditNote

        for credit_note in credit_notes:
            if not isinstance(credit_note, _CreditNote):
                raise TypeError("The credit note must be of type CreditNote")

            total_value += credit_note.value()

        if receipted_value is None:
            receipted_value = total_value
        else:
            receipted_value = _create_decimal(receipted_value)

        if receipted_value < 0:
            raise ValueError("You cannot receipt a value that is less "
                             "than zero! %s" % receipted_value)
        elif receipted_value > total_value:
            raise ValueError("You cannot receipt a value that is greater "
                             "than the value of the original credit "
                             "notes - %s versus %s" %
                             (receipted_value, total_value))

        receipts = []

        if receipted_value == total_value:
            for credit_note in credit_notes:
                receipts.append(Receipt(credit_note, authorisation))
        else:
            diff = total_value - receipted_value

            for credit_note in credit_notes:
                d = min(diff, credit_note.value())

                diff -= d
                r = credit_note.value() - d

                receipts.append(Receipt(credit_note, authorisation, r))

        return receipts
コード例 #27
0
    def from_key(key):
        """Extract information from the passed object store key.

           This looks for a string that is;

           isoformat_datetime/UID/transactioncode

           where transactioncode is a string that matches
           '2 letters followed by a number'

           CL000100.005000
           DR000004.234100

           etc.

           For sent and received receipts there are two values;
           the receipted value and the original estimate. These
           have the standard format if the values are the same, e.g.

           RR000100.005000

           however, they have original value T receipted value if they are
           different, e.g.

           RR000100.005000T000090.000000

           Args:
                key: Object store key

        """
        from Acquire.ObjectStore import string_to_datetime \
            as _string_to_datetime
        from Acquire.Accounting import create_decimal as _create_decimal

        parts = key.split("/")

        # start at the end...
        nparts = len(parts)
        for i in range(0, nparts):
            j = nparts - i - 1
            t = TransactionInfo()

            try:
                t._datetime = _string_to_datetime(parts[j - 2])
            except:
                continue

            t._uid = parts[j - 1]

            part = parts[j]
            try:
                code = TransactionInfo._get_code(part[0:2])

                if code == TransactionCode.SENT_RECEIPT or \
                   code == TransactionCode.RECEIVED_RECEIPT:
                    values = part[2:].split("T")
                    try:
                        value = _create_decimal(values[0])
                        receipted_value = _create_decimal(values[1])
                        t._code = code
                        t._value = value
                        t._receipted_value = receipted_value
                        return t
                    except:
                        pass

                value = _create_decimal(part[2:])

                t._code = code
                t._value = value
                t._receipted_value = None

                return t
            except:
                pass

        raise ValueError("Cannot extract transaction info from '%s'" % (key))