Example #1
0
    def test_create_relationships(self):
        a = Account.objects.get(pk=4)
        p = Payee.objects.get(pk=5)
        t = Transaction(account=a,
                        mobile=False,
                        payee=p,
                        amount=Decimal('-50'),
                        date=datetime.date.today())
        t.save()

        TagLink.create_relationships(
            t, u' food:26.30 toiletries:12.98\n household:51.23')

        expected = [{
            'name': 'food',
            'split': Decimal('-26.30')
        }, {
            'name': 'toiletries',
            'split': Decimal('-12.98')
        }, {
            'name': 'household',
            'split': Decimal('-50')
        }]

        results = TagLink.objects.select_related().filter(
            transaction=t).order_by('id')

        self.assertEqual(len(results), len(expected))

        for t in range(len(results)):
            self.assertEqual(results[t].tag.name, expected[t]['name'])
            self.assertEqual(results[t].split, expected[t]['split'])
Example #2
0
    def test_add_negative(self):
        a = Account.objects.get(pk=1)
        p = Payee.objects.get(pk=1)
        t = Transaction(account=a, mobile=False, payee=p, amount=Decimal("-512.78"), date=datetime.date.today())
        t.save()

        a = Account.objects.get(pk=1)

        self.assertEqual(a.balance, Decimal("3188.77"))
Example #3
0
    def test_add_negative(self):
        a = Account.objects.get(pk=1)
        p = Payee.objects.get(pk=1)
        t = Transaction(account=a,
                        mobile=False,
                        payee=p,
                        amount=Decimal('-512.78'),
                        date=datetime.date.today())
        t.save()

        a = Account.objects.get(pk=1)

        self.assertEqual(a.balance, Decimal('3188.77'))
Example #4
0
    def test_create_relationships(self):
        a = Account.objects.get(pk=4)
        p = Payee.objects.get(pk=5)
        t = Transaction(account=a, mobile=False, payee=p, amount=Decimal("-50"), date=datetime.date.today())
        t.save()

        TagLink.create_relationships(t, u" food:26.30 toiletries:12.98\n household:51.23")

        expected = [
            {"name": "food", "split": Decimal("-26.30")},
            {"name": "toiletries", "split": Decimal("-12.98")},
            {"name": "household", "split": Decimal("-50")},
        ]

        results = TagLink.objects.select_related().filter(transaction=t).order_by("id")

        self.assertEqual(len(results), len(expected))

        for t in range(len(results)):
            self.assertEqual(results[t].tag.name, expected[t]["name"])
            self.assertEqual(results[t].split, expected[t]["split"])
Example #5
0
    def test_update_balance(self):
        # Make sure the Transaction model doesn't update the account
        Transaction.listen_off()

        # Delete the first transaction (827.59 of credit)
        t = Transaction.objects.select_related().get(pk=1)
        t.delete()
        a = t.account

        # The balance shouldn't have changed
        self.assertEqual(a.balance, Decimal('3701.55'))

        # Update the balance, only taking into account new transactions
        a.update_balance(all=False)

        # The balance still shouldn't have changed
        self.assertEqual(a.balance, Decimal('3701.55'))

        # Create a new transaction
        p = Payee.objects.get(pk=1)
        t = Transaction(account=a,
                        mobile=False,
                        payee=p,
                        amount=Decimal('300'),
                        date=datetime.date.today())
        t.save()

        # Update the balance once more
        a.update_balance(all=False)

        # The balance should now be +300 from the added transaction
        self.assertEqual(a.balance, Decimal('4001.55'))

        # Update the balance a final time
        a.update_balance(all=True)

        # The balance should now be completely up-to-date
        self.assertEqual(a.balance, Decimal('3173.96'))

        # Turn transaction listening back on for other tests
        Transaction.listen_on()
Example #6
0
    def test_add_lots(self):
        """
        Simulates a synchronisation of a large amount of transactions
        """
        a = Account.objects.get(pk=1)
        p = Payee.objects.get(pk=1)

        total = a.balance
        orig = total.copy_abs()

        count = Transaction.objects.all().count()

        # Turn the signal listening off so we can update the account balance afterwards
        Transaction.listen_off()

        for i in range(1, 100):
            amount = Decimal('%.2f' % i)
            if i > 50:
                amount = amount.copy_negate()

            t = Transaction(account=a,
                            mobile=False,
                            payee=p,
                            amount=amount,
                            date=datetime.date.today())
            t.save()

            total += amount
            count += 1

        # Turn signal listening back on
        Transaction.listen_on()

        a = Account.objects.get(pk=1)

        # Make sure the balance hasn't been updated
        self.assertEqual(a.balance, orig)

        # Make sure the right number of transactions has been added
        self.assertEqual(Transaction.objects.all().count(), count)
Example #7
0
    def test_update_balance(self):
        # Make sure the Transaction model doesn't update the account
        Transaction.listen_off()

        # Delete the first transaction (827.59 of credit)
        t = Transaction.objects.select_related().get(pk=1)
        t.delete()
        a = t.account

        # The balance shouldn't have changed
        self.assertEqual(a.balance, Decimal("3701.55"))

        # Update the balance, only taking into account new transactions
        a.update_balance(all=False)

        # The balance still shouldn't have changed
        self.assertEqual(a.balance, Decimal("3701.55"))

        # Create a new transaction
        p = Payee.objects.get(pk=1)
        t = Transaction(account=a, mobile=False, payee=p, amount=Decimal("300"), date=datetime.date.today())
        t.save()

        # Update the balance once more
        a.update_balance(all=False)

        # The balance should now be +300 from the added transaction
        self.assertEqual(a.balance, Decimal("4001.55"))

        # Update the balance a final time
        a.update_balance(all=True)

        # The balance should now be completely up-to-date
        self.assertEqual(a.balance, Decimal("3173.96"))

        # Turn transaction listening back on for other tests
        Transaction.listen_on()
Example #8
0
    def test_add_lots(self):
        """
        Simulates a synchronisation of a large amount of transactions
        """
        a = Account.objects.get(pk=1)
        p = Payee.objects.get(pk=1)

        total = a.balance
        orig = total.copy_abs()

        count = Transaction.objects.all().count()

        # Turn the signal listening off so we can update the account balance afterwards
        Transaction.listen_off()

        for i in range(1, 100):
            amount = Decimal("%.2f" % i)
            if i > 50:
                amount = amount.copy_negate()

            t = Transaction(account=a, mobile=False, payee=p, amount=amount, date=datetime.date.today())
            t.save()

            total += amount
            count += 1

        # Turn signal listening back on
        Transaction.listen_on()

        a = Account.objects.get(pk=1)

        # Make sure the balance hasn't been updated
        self.assertEqual(a.balance, orig)

        # Make sure the right number of transactions has been added
        self.assertEqual(Transaction.objects.all().count(), count)
Example #9
0
def get_transactions(request):
    # Check the validity of the request
    if request.method != u'POST' or 'username' not in request.POST.keys() or 'password' not in request.POST.keys() or 'transactions' not in request.POST.keys():
        return HttpResponseBadRequest(u"Either you didn't POST or you didn't give your username and your password")
    
    try:
        user = User.objects.get(username=request.POST['username'])
    except User.DoesNotExist:
        return HttpResponseForbidden()

    # Check the username and password given
    if not check_password(request.POST['password'], user.password):
        return HttpResponseForbidden()
    
    # Set up some variables
    accounts = {}
    # errors will contain a list of integers corresponding to the transaction's number
    # That way, clients can determine which transactions were successfully received and 
    # committed to the database
    errors = []
    
    try:
        transactions = json.loads(request.POST['transactions'])
    except ValueError:
        # We couldn't get a valid JSON object
        return HttpResponseBadRequest(u'Could not load the transactions as a JSON object')
    
    if type(transactions) is not list:
        return HttpResponseBadRequest(u'Transactions is not a list')
    
    # Turn signal listening off so that account balances aren't updated
    Transaction.listen_off()
    
    # Go through each transaction we've been sent
    for i in range(len(transactions)):
        if type(transactions[i]) is not dict:
            return HttpResponseBadRequest(u'Element %d of transactions is not a dictionary' % i)
        
        # If we don't have an account, we can't do anything
        if 'account' not in transactions[i].keys():
            errors.append(i)
            continue
        else:
            # If we already know about this account, we can get if from the 'cache'
            if transactions[i]['account'] in accounts.keys():
                account = accounts[transactions[i]['account']]
            else:
                # Otherwise we need to try and find it from the database
                try:
                    account = Account.objects.get(pk=transactions[i]['account'])
                    accounts[account.id] = account
                except Account.DoesNotExist:
                    # If it doesn't appear in the database, add the transaction's number
                    # to the list of errors and continue
                    errors.append(i)
                    continue
        
        # Make sure we have enough information to continue
        if 'payee' not in transactions[i].keys() or 'amount' not in transactions[i].keys():
            errors.append(i)
            continue
        
        # Set up the new Transaction
        t = Transaction(mobile=True, account=account, transfer=False)
        
        # Get the payee's name and make sure it's UTF8
        pname = transactions[i]['payee']
        if type(pname) is str:
            pname = pname.decode('utf-8')
            
        # Try to find an existing payee with that name
        try:
            payee = Payee.objects.get(name__iexact=pname)
        except Payee.DoesNotExist:
            # Create a new payee
            payee = Payee(name=pname)
            payee.save()

        t.payee = payee
        t.amount = '%s' % transactions[i]['amount']
        
        # If credit doesn't appear in the keys, assume it's a negative value
        if 'credit' not in transactions[i].keys():
            t.amount = '%s' % (-abs(float(t.amount)))
        else:
            # Otherwise if credit is anything but 0 assume it's a positive value
            if transactions[i]['credit'] == 0:
                t.amount = '%s' % (-abs(float(t.amount)))
            else:
                t.amount = '%s' % abs(float(t.amount))
        
        # Try to get the date from the POSTed values
        try:
            t.date = datetime.date.fromtimestamp(float(transactions[i]['date']))
        except KeyError, ValueError:
            # KeyError means we don't have one in the POST data
            # ValueError means we couldn't decode it
            t.date = datetime.date.today()
            
        # If we have a comment, decode it
        if 'comment' in transactions[i].keys():
            comment = transactions[i]['comment']
            if type(comment) is str:
                comment = comment.decode('utf-8')
            t.comment = comment
            
        t.save()
Example #10
0
         # Otherwise if credit is anything but 0 assume it's a positive value
         if transactions[i]['credit'] == 0:
             t.amount = '%s' % (-abs(float(t.amount)))
         else:
             t.amount = '%s' % abs(float(t.amount))
     
     # Try to get the date from the POSTed values
     try:
         t.date = datetime.date.fromtimestamp(float(transactions[i]['date']))
     except KeyError, ValueError:
         # KeyError means we don't have one in the POST data
         # ValueError means we couldn't decode it
         t.date = datetime.date.today()
         
     # If we have a comment, decode it
     if 'comment' in transactions[i].keys():
         comment = transactions[i]['comment']
         if type(comment) is str:
             comment = comment.decode('utf-8')
         t.comment = comment
         
     t.save()
 
 # Turn signal listening back on
 Transaction.listen_on()
 
 # Now we can update the balance of all the accounts we've dealt with
 for a in accounts:
     accounts[a].update_balance()
 
 return HttpResponse(json.dumps({'errors': errors}), content_type='application/javascript; charset=utf-8')
Example #11
0
def get_transactions(request):
    # Check the validity of the request
    if request.method != u'POST' or 'username' not in request.POST.keys(
    ) or 'password' not in request.POST.keys(
    ) or 'transactions' not in request.POST.keys():
        return HttpResponseBadRequest(
            u"Either you didn't POST or you didn't give your username and your password"
        )

    try:
        user = User.objects.get(username=request.POST['username'])
    except User.DoesNotExist:
        return HttpResponseForbidden()

    # Check the username and password given
    if not check_password(request.POST['password'], user.password):
        return HttpResponseForbidden()

    # Set up some variables
    accounts = {}
    # errors will contain a list of integers corresponding to the transaction's number
    # That way, clients can determine which transactions were successfully received and
    # committed to the database
    errors = []

    try:
        transactions = json.loads(request.POST['transactions'])
    except ValueError:
        # We couldn't get a valid JSON object
        return HttpResponseBadRequest(
            u'Could not load the transactions as a JSON object')

    if type(transactions) is not list:
        return HttpResponseBadRequest(u'Transactions is not a list')

    # Turn signal listening off so that account balances aren't updated
    Transaction.listen_off()

    # Go through each transaction we've been sent
    for i in range(len(transactions)):
        if type(transactions[i]) is not dict:
            return HttpResponseBadRequest(
                u'Element %d of transactions is not a dictionary' % i)

        # If we don't have an account, we can't do anything
        if 'account' not in transactions[i].keys():
            errors.append(i)
            continue
        else:
            # If we already know about this account, we can get if from the 'cache'
            if transactions[i]['account'] in accounts.keys():
                account = accounts[transactions[i]['account']]
            else:
                # Otherwise we need to try and find it from the database
                try:
                    account = Account.objects.get(
                        pk=transactions[i]['account'])
                    accounts[account.id] = account
                except Account.DoesNotExist:
                    # If it doesn't appear in the database, add the transaction's number
                    # to the list of errors and continue
                    errors.append(i)
                    continue

        # Make sure we have enough information to continue
        if 'payee' not in transactions[i].keys(
        ) or 'amount' not in transactions[i].keys():
            errors.append(i)
            continue

        # Set up the new Transaction
        t = Transaction(mobile=True, account=account, transfer=False)

        # Get the payee's name and make sure it's UTF8
        pname = transactions[i]['payee']
        if type(pname) is str:
            pname = pname.decode('utf-8')

        # Try to find an existing payee with that name
        try:
            payee = Payee.objects.get(name__iexact=pname)
        except Payee.DoesNotExist:
            # Create a new payee
            payee = Payee(name=pname)
            payee.save()

        t.payee = payee
        t.amount = '%s' % transactions[i]['amount']

        # If credit doesn't appear in the keys, assume it's a negative value
        if 'credit' not in transactions[i].keys():
            t.amount = '%s' % (-abs(float(t.amount)))
        else:
            # Otherwise if credit is anything but 0 assume it's a positive value
            if transactions[i]['credit'] == 0:
                t.amount = '%s' % (-abs(float(t.amount)))
            else:
                t.amount = '%s' % abs(float(t.amount))

        # Try to get the date from the POSTed values
        try:
            t.date = datetime.date.fromtimestamp(float(
                transactions[i]['date']))
        except KeyError, ValueError:
            # KeyError means we don't have one in the POST data
            # ValueError means we couldn't decode it
            t.date = datetime.date.today()

        # If we have a comment, decode it
        if 'comment' in transactions[i].keys():
            comment = transactions[i]['comment']
            if type(comment) is str:
                comment = comment.decode('utf-8')
            t.comment = comment

        t.save()
Example #12
0
            else:
                t.amount = '%s' % abs(float(t.amount))

        # Try to get the date from the POSTed values
        try:
            t.date = datetime.date.fromtimestamp(float(
                transactions[i]['date']))
        except KeyError, ValueError:
            # KeyError means we don't have one in the POST data
            # ValueError means we couldn't decode it
            t.date = datetime.date.today()

        # If we have a comment, decode it
        if 'comment' in transactions[i].keys():
            comment = transactions[i]['comment']
            if type(comment) is str:
                comment = comment.decode('utf-8')
            t.comment = comment

        t.save()

    # Turn signal listening back on
    Transaction.listen_on()

    # Now we can update the balance of all the accounts we've dealt with
    for a in accounts:
        accounts[a].update_balance()

    return HttpResponse(json.dumps({'errors': errors}),
                        content_type='application/javascript; charset=utf-8')