Example #1
0
 def balance(self, username):
     """
     Return a list :
         [ <balance in account currency>, <balance in preferred currency> ]
     """
     balance = db.session.query(
         db.func.sum(TransactionAccount.amount)
     ).filter(
         TransactionAccount.account_id == self.id
     ).one()[0]
     if balance:
         balances = [ self.start_balance + balance ]
     else:
         balances = [ self.start_balance ]
     balances.append(
         helpers.rate(
             username,
             self.currency.isocode,
             coremodels.User.query.options(
                 db.joinedload(coremodels.User.preferred_currency)
             ).get(
                 username
             ).preferred_currency.isocode
         ) * balances[0]
     )
     return balances
Example #2
0
 def http_rate(self, fromisocode, toisocode):
     response = helpers.rate(self.username, fromisocode, toisocode)
     if response:
         return jsonify(
                     status=200,
                     response=response
             )
     else:
         self.badrequest("Rate cannot be calculated")
Example #3
0
 def update(self, categoryid):
     category = self.__own_category(categoryid)
     if not category:
         self.notfound(
           'Nonexistent category cannot be modified (or you do not own it)')
     if 'name' in self.args:
         category.name = self.args['name']
     if 'currency' in self.args:
         currency = core.Currency.query.filter(
             db.and_(
                 core.Currency.isocode == self.args['currency'],
                 db.or_(
                     core.Currency.owner_username == self.username,
                     core.Currency.owner_username == None
                 )
             )
         ).first()
         if currency:
             rate = helpers.rate(
                         self.username,
                         category.currency.isocode,
                         currency.isocode
                    )
             category.currency = currency
             for tc in models.TransactionCategory.query.filter(
                         models.TransactionCategory.category == category
                       ).all():
                 tc.category_amount = tc.category_amount * rate
     if 'parent' in self.args:
         if self.args['parent'] == 'NONE':
             category.parent_id = None
         else:
             parent = self.__own_category(self.args['parent'])
             if not parent:
                 self.badrequest("This parent category does not exist")
             if category.contains_category(parent.id):
                 self.badrequest(
                           "The parent is already a child of this category")
             if parent.id != category.parent_id:
                 allparents = set([parent.id, category.parent_id] + \
                                  parent.all_parents_ids())
                 if category.parent_id:
                     allparents.update(category.parent.all_parents_ids())
                 for parentid in allparents:
                     if parentid:
                         self.add_to_response('categoriesbalance', parentid)
                 category.parent = parent
     db.session.commit()
     return category.as_dict(self.username)
Example #4
0
def totalbalance(username):
    accounts = models.Account.query.options(
        db.joinedload(models.Account.currency)).join(
            models.AccountOwner).filter(
                models.AccountOwner.owner_username == username).all()
    # Calculate the total balance, in the user's preferred currency
    totalbalance = 0
    totalcurrency = core.User.query.options(
        db.joinedload(
            core.User.preferred_currency)).get(username).preferred_currency
    for account in accounts:
        totalbalance += account.balance(username)[0] * \
        helpers.rate(username,
                     account.currency.isocode,
                     totalcurrency.isocode)
    return {'balance': totalbalance, 'currency': totalcurrency.isocode}
Example #5
0
 def balance(self, username):
     """
     Return a list :
         [ <balance in account currency>, <balance in preferred currency> ]
     """
     balance = db.session.query(db.func.sum(
         TransactionAccount.amount)).filter(
             TransactionAccount.account_id == self.id).one()[0]
     if balance:
         balances = [self.start_balance + balance]
     else:
         balances = [self.start_balance]
     balances.append(
         helpers.rate(
             username, self.currency.isocode,
             coremodels.User.query.options(
                 db.joinedload(coremodels.User.preferred_currency)).get(
                     username).preferred_currency.isocode) * balances[0])
     return balances
Example #6
0
 def update(self, categoryid):
     category = self.__own_category(categoryid)
     if not category:
         self.notfound(
             'Nonexistent category cannot be modified (or you do not own it)'
         )
     if 'name' in self.args:
         category.name = self.args['name']
     if 'currency' in self.args:
         currency = core.Currency.query.filter(
             db.and_(
                 core.Currency.isocode == self.args['currency'],
                 db.or_(core.Currency.owner_username == self.username,
                        core.Currency.owner_username == None))).first()
         if currency:
             rate = helpers.rate(self.username, category.currency.isocode,
                                 currency.isocode)
             category.currency = currency
             for tc in models.TransactionCategory.query.filter(
                     models.TransactionCategory.category == category).all():
                 tc.category_amount = tc.category_amount * rate
     if 'parent' in self.args:
         if self.args['parent'] == 'NONE':
             category.parent_id = None
         else:
             parent = self.__own_category(self.args['parent'])
             if not parent:
                 self.badrequest("This parent category does not exist")
             if category.contains_category(parent.id):
                 self.badrequest(
                     "The parent is already a child of this category")
             if parent.id != category.parent_id:
                 allparents = set([parent.id, category.parent_id] + \
                                  parent.all_parents_ids())
                 if category.parent_id:
                     allparents.update(category.parent.all_parents_ids())
                 for parentid in allparents:
                     if parentid:
                         self.add_to_response('categoriesbalance', parentid)
                 category.parent = parent
     db.session.commit()
     return category.as_dict(self.username)
Example #7
0
def totalbalance(username):
    accounts = models.Account.query.options(
                    db.joinedload(models.Account.currency)
    ).join(models.AccountOwner).filter(
        models.AccountOwner.owner_username == username
    ).all()
    # Calculate the total balance, in the user's preferred currency
    totalbalance = 0
    totalcurrency = core.User.query.options(
                        db.joinedload(core.User.preferred_currency)
                    ).get(username).preferred_currency
    for account in accounts:
        totalbalance += account.balance(username)[0] * \
        helpers.rate(username,
                     account.currency.isocode,
                     totalcurrency.isocode)
    return {
        'balance': totalbalance,
        'currency': totalcurrency.isocode
    }
Example #8
0
    def balance(self, username):
        today = datetime.date.today()

        balance = cache.get('categorybalance-{0}'.format(self.id))

        if not balance:
            balance = {'currency': self.currency.isocode}
            balance['year'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)
            ).filter(
                db.and_(
                    TransactionCategory.category_id == self.id,
                    TransactionCategory.transaction_id == Transaction.id,
                    Transaction.date.between(
                        datetime.date(today.year, 1, 1),
                        datetime.date(today.year, 12, 31)
                    )
                )
            ).one()[0] or 0

            if today.month == 12:
                lastdayofmonth = datetime.date(today.year, 12, 31)
            else:
                lastdayofmonth = datetime.date(today.year, today.month+1, 1) -\
                                                          datetime.timedelta(1)
            balance['month'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)
            ).filter(
                db.and_(
                    TransactionCategory.category_id == self.id,
                    TransactionCategory.transaction_id == Transaction.id,
                    Transaction.date.between(
                        datetime.date(today.year, today.month, 1),
                        lastdayofmonth
                    )
                )
            ).one()[0] or 0

            firstdayofweek = today - datetime.timedelta(today.weekday())
            lastdayofweek = today + datetime.timedelta(6-today.weekday())
            balance['week'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)
            ).filter(
                db.and_(
                    TransactionCategory.category_id == self.id,
                    TransactionCategory.transaction_id == Transaction.id,
                    Transaction.date.between(
                        firstdayofweek,
                        lastdayofweek
                    )
                )
            ).one()[0] or 0

            balance['7days'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)
            ).filter(
                db.and_(
                    TransactionCategory.category_id == self.id,
                    TransactionCategory.transaction_id == Transaction.id,
                    Transaction.date.between(
                        today - datetime.timedelta(6),
                        today
                    )
                )
            ).one()[0] or 0

            balance['30days'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)
            ).filter(
                db.and_(
                    TransactionCategory.category_id == self.id,
                    TransactionCategory.transaction_id == Transaction.id,
                    Transaction.date.between(
                        today - datetime.timedelta(29),
                        today
                    )
                )
            ).one()[0] or 0

            # Cache the balance only for 5 seconds : it helps when listing
            # multiple categories by reducing sql requests
            cache.set('categorybalance-{0}'.format(self.id), balance, 5)

        for child in self.children:
            child_balance = child.balance(username)
            rate = helpers.rate(username,
                              child_balance['currency'], self.currency.isocode)
            balance['year'] = balance['year'] + child_balance['year'] * rate
            balance['month'] = balance['month'] + child_balance['month'] * rate
            balance['week'] = balance['week'] + child_balance['week'] * rate
            balance['7days'] = balance['7days'] + child_balance['7days'] * rate
            balance['30days'] = balance['30days'] +child_balance['30days']*rate

        return balance
Example #9
0
    def balance(self, username):
        today = datetime.date.today()

        balance = cache.get('categorybalance-{0}'.format(self.id))

        if not balance:
            balance = {'currency': self.currency.isocode}
            balance['year'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)).filter(
                    db.and_(
                        TransactionCategory.category_id == self.id,
                        TransactionCategory.transaction_id == Transaction.id,
                        Transaction.date.between(
                            datetime.date(today.year, 1, 1),
                            datetime.date(today.year, 12, 31)))).one()[0] or 0

            if today.month == 12:
                lastdayofmonth = datetime.date(today.year, 12, 31)
            else:
                lastdayofmonth = datetime.date(today.year, today.month+1, 1) -\
                                                          datetime.timedelta(1)
            balance['month'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)).filter(
                    db.and_(
                        TransactionCategory.category_id == self.id,
                        TransactionCategory.transaction_id == Transaction.id,
                        Transaction.date.between(
                            datetime.date(today.year, today.month, 1),
                            lastdayofmonth))).one()[0] or 0

            firstdayofweek = today - datetime.timedelta(today.weekday())
            lastdayofweek = today + datetime.timedelta(6 - today.weekday())
            balance['week'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)).filter(
                    db.and_(
                        TransactionCategory.category_id == self.id,
                        TransactionCategory.transaction_id == Transaction.id,
                        Transaction.date.between(firstdayofweek,
                                                 lastdayofweek))).one()[0] or 0

            balance['7days'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)).filter(
                    db.and_(
                        TransactionCategory.category_id == self.id,
                        TransactionCategory.transaction_id == Transaction.id,
                        Transaction.date.between(today - datetime.timedelta(6),
                                                 today))).one()[0] or 0

            balance['30days'] = db.session.query(
                db.func.sum(TransactionCategory.category_amount)).filter(
                    db.and_(
                        TransactionCategory.category_id == self.id,
                        TransactionCategory.transaction_id == Transaction.id,
                        Transaction.date.between(
                            today - datetime.timedelta(29),
                            today))).one()[0] or 0

            # Cache the balance only for 5 seconds : it helps when listing
            # multiple categories by reducing sql requests
            cache.set('categorybalance-{0}'.format(self.id), balance, 5)

        for child in self.children:
            child_balance = child.balance(username)
            rate = helpers.rate(username, child_balance['currency'],
                                self.currency.isocode)
            balance['year'] = balance['year'] + child_balance['year'] * rate
            balance['month'] = balance['month'] + child_balance['month'] * rate
            balance['week'] = balance['week'] + child_balance['week'] * rate
            balance['7days'] = balance['7days'] + child_balance['7days'] * rate
            balance[
                '30days'] = balance['30days'] + child_balance['30days'] * rate

        return balance
Example #10
0
def create(username, wizard, locale, prefcurrency):
    """Create entries from wizard files"""

    # /!\ Does not work in Python < 2.7
    #
    # (sections order is important)

    ########## Initialization
    data = ConfigParser.RawConfigParser()
    if wizard in ('basic', 'demo'):
        try:
            datafile = codecs.open(
                            os.path.join(config.WIZARD_DATA,'%s.basic'%locale),
                            'r', 'utf8'
                        )
            data.readfp(datafile)
            datafile.close()
        except:
            abort(400)
    if wizard == 'demo':
        try:
            datafile = codecs.open(
                            os.path.join(config.WIZARD_DATA, '%s.demo'%locale),
                            'r', 'utf8'
                        )
            data.readfp(datafile)
            datafile.close()
        except:
            abort(400)
    sections = data.sections()
    if not sections:
        return 200, 'OK'
    try:
        preferred_currency = core.Currency.query.filter(
                                    db.and_(
                                        core.Currency.isocode == prefcurrency,
                                        core.Currency.owner_username == None
                                    )
                                ).one()
    except:
        abort(400)

    today = datetime.date.today()

    ########## Helper functions
    def subsections(name):
        return [ i for i in sections if i.startswith(name) ]

    ########## Currency
    currencies = { prefcurrency: preferred_currency }
    for cur in subsections('currency-'):
        symbol = data.get(cur, 'symbol')
        currency = core.Currency(
                        owner_username = username,
                        isocode = symbol,
                        symbol = symbol,
                        name = data.get(cur, 'name'),
                        rate = data.get(cur, 'rate')
                    )
        db.session.add(currency)
        currencies[symbol] = currency
    db.session.commit()

    ########## Account
    accounts = {}
    for acc in subsections('account-'):
        if data.has_option(acc, 'currency'):
            curname = data.get(acc, 'currency')
            if curname not in currencies:
                currencies[curname] = core.Currency.query.filter(
                    db.and_(
                        core.Currency.owner_username == None,
                        core.Currency.isocode == curname
                    )
                ).one()
        else:
            curname = prefcurrency
        account = transaction.Account(
            name = data.get(acc, 'name'),
            currency = currencies[curname],
            start_balance = data.get(acc, 'balance')
        )
        db.session.add(account)
        accounts[acc.split('-')[1]] = account
        db.session.add(
            transaction.AccountOwner(
                account = account,
                owner_username = username
            )
        )
    db.session.commit()

    ########## Category
    categories = {}
    for cat in subsections('category-'):
        if data.has_option(cat, 'currency'):
            curname = data.get(cat, 'currency')
            if curname not in currencies:
                currencies[curname] = core.Currency.query.filter(
                    db.and_(
                        core.Currency.owner_username == None,
                        core.Currency.isocode == curname
                    )
                ).one()
        else:
            curname = prefcurrency
        category = transaction.Category(
            owner_username = username,
            currency = currencies[curname],
            name = data.get(cat, 'name')
        )
        try:
            category.parent = categories[data.get(cat, 'parent')]
        except:
            pass
        db.session.add(category)
        categories[cat.split('-')[1]] = category
    db.session.commit()

    ########## Transaction
    for tra in subsections('transaction-'):
        if data.has_option(tra, 'currency'):
            curname = data.get(tra, 'currency')
            if curname not in currencies:
                currencies[curname] = core.Currency.query.filter(
                    db.and_(
                        core.Currency.owner_username == None,
                        core.Currency.isocode == curname
                    )
                ).one()
        else:
            curname = prefcurrency
        currency = currencies[curname]
        # Calculate date
        year, month, day = data.get(tra, 'date').split('/')
        # Month
        if month:
            if month[0] in ('-', '+'):
                month = today.month + int(month)
            else:
                month = int(month)
        else:
            month = today.month
        # Year
        if year:
            if year[0] in ('-', '+'):
                year = today.year + int(year)
            elif year == '?':
                # If year = "?", point to the last passed year containing the
                # defined month (either current year or previous year)
                if month < today.month:
                    year = today.year
                else:
                    year = today.year - 1
            else:
                year = int(year)
        else:
            year = today.year
        # Check the month is not outside bounds, or correct the year
        def month_outside_bounds(month, year):
            if month < 1:
                month = month + 12
                year = year - 1
                month, year = month_outside_bounds(month, year)
            elif month > 12:
                month = month - 12
                year = year + 1
                month, year = month_outside_bounds(month, year)
            return month, year
        month, year = month_outside_bounds(month, year)
        # Day
        if day:
            if day[0] in ('-', '+'):
                daydeltafromfirst = today.day + int(day) - 1
                day = 1
            else:
                daydeltafromfirst = int(day) - 1
                day = 1
        else:
            day = today.day
            daydeltafromfirst = 0
        transactiondate = datetime.date(year,month,day)
        if daydeltafromfirst:
            transactiondate = transactiondate + \
                              datetime.timedelta(days=daydeltafromfirst)
        # Create transaction
        trans = transaction.Transaction(
            owner_username = username,
            description = data.get(tra, 'description'),
            amount = data.get(tra, 'amount'),
            currency = currency,
            date = transactiondate
        )
        try:
            trans.original_description = data.get(tra, 'original_description')
        except:
            trans.original_description = data.get(tra, 'description')
        db.session.add(trans)
        # Links to accounts
        for accountdata in data.get(tra, 'accounts').split():
            accountdatatb = accountdata.split(':')
            accountnum = accountdatatb[0]
            if len(accountdatatb) > 1:
                amount = accountdatatb[1]
            else:
                amount = trans.amount
            account = accounts[accountnum]
            accountamount = amount * helpers.rate(
                                            username,
                                            currency.isocode,
                                            account.currency.isocode
                                        )
            db.session.add(
                transaction.TransactionAccount(
                    transaction = trans,
                    account = account,
                    amount = accountamount
                )
            )
        # Links to categories
        for categorydata in data.get(tra, 'categories').split():
            categorydatatb = categorydata.split(':')
            categorynum = categorydatatb[0]
            if len(categorydatatb) > 1:
                amount = categorydatatb[1]
            else:
                amount = trans.amount
            category = categories[categorynum]
            categoryamount = amount * helpers.rate(
                                            username,
                                            currency.isocode,
                                            category.currency.isocode
                                        )
            db.session.add(
                transaction.TransactionCategory(
                    transaction = trans,
                    category = category,
                    transaction_amount = amount,
                    category_amount = categoryamount
                )
            )
    db.session.commit()

    ########## OK, finished
    return 200, 'OK'
Example #11
0
 def http_rate(self, fromisocode, toisocode):
     response = helpers.rate(self.username, fromisocode, toisocode)
     if response:
         return jsonify(status=200, response=response)
     else:
         self.badrequest("Rate cannot be calculated")
Example #12
0
def create(username, wizard, locale, prefcurrency):
    """Create entries from wizard files"""

    # /!\ Does not work in Python < 2.7
    #
    # (sections order is important)

    ########## Initialization
    data = ConfigParser.RawConfigParser()
    if wizard in ('basic', 'demo'):
        try:
            datafile = codecs.open(
                os.path.join(config.WIZARD_DATA, '%s.basic' % locale), 'r',
                'utf8')
            data.readfp(datafile)
            datafile.close()
        except:
            abort(400)
    if wizard == 'demo':
        try:
            datafile = codecs.open(
                os.path.join(config.WIZARD_DATA, '%s.demo' % locale), 'r',
                'utf8')
            data.readfp(datafile)
            datafile.close()
        except:
            abort(400)
    sections = data.sections()
    if not sections:
        return 200, 'OK'
    try:
        preferred_currency = core.Currency.query.filter(
            db.and_(core.Currency.isocode == prefcurrency,
                    core.Currency.owner_username == None)).one()
    except:
        abort(400)

    today = datetime.date.today()

    ########## Helper functions
    def subsections(name):
        return [i for i in sections if i.startswith(name)]

    ########## Currency
    currencies = {prefcurrency: preferred_currency}
    for cur in subsections('currency-'):
        symbol = data.get(cur, 'symbol')
        currency = core.Currency(owner_username=username,
                                 isocode=symbol,
                                 symbol=symbol,
                                 name=data.get(cur, 'name'),
                                 rate=data.get(cur, 'rate'))
        db.session.add(currency)
        currencies[symbol] = currency
    db.session.commit()

    ########## Account
    accounts = {}
    for acc in subsections('account-'):
        if data.has_option(acc, 'currency'):
            curname = data.get(acc, 'currency')
            if curname not in currencies:
                currencies[curname] = core.Currency.query.filter(
                    db.and_(core.Currency.owner_username == None,
                            core.Currency.isocode == curname)).one()
        else:
            curname = prefcurrency
        account = transaction.Account(name=data.get(acc, 'name'),
                                      currency=currencies[curname],
                                      start_balance=data.get(acc, 'balance'))
        db.session.add(account)
        accounts[acc.split('-')[1]] = account
        db.session.add(
            transaction.AccountOwner(account=account, owner_username=username))
    db.session.commit()

    ########## Category
    categories = {}
    for cat in subsections('category-'):
        if data.has_option(cat, 'currency'):
            curname = data.get(cat, 'currency')
            if curname not in currencies:
                currencies[curname] = core.Currency.query.filter(
                    db.and_(core.Currency.owner_username == None,
                            core.Currency.isocode == curname)).one()
        else:
            curname = prefcurrency
        category = transaction.Category(owner_username=username,
                                        currency=currencies[curname],
                                        name=data.get(cat, 'name'))
        try:
            category.parent = categories[data.get(cat, 'parent')]
        except:
            pass
        db.session.add(category)
        categories[cat.split('-')[1]] = category
    db.session.commit()

    ########## Transaction
    for tra in subsections('transaction-'):
        if data.has_option(tra, 'currency'):
            curname = data.get(tra, 'currency')
            if curname not in currencies:
                currencies[curname] = core.Currency.query.filter(
                    db.and_(core.Currency.owner_username == None,
                            core.Currency.isocode == curname)).one()
        else:
            curname = prefcurrency
        currency = currencies[curname]
        # Calculate date
        year, month, day = data.get(tra, 'date').split('/')
        # Month
        if month:
            if month[0] in ('-', '+'):
                month = today.month + int(month)
            else:
                month = int(month)
        else:
            month = today.month
        # Year
        if year:
            if year[0] in ('-', '+'):
                year = today.year + int(year)
            elif year == '?':
                # If year = "?", point to the last passed year containing the
                # defined month (either current year or previous year)
                if month < today.month:
                    year = today.year
                else:
                    year = today.year - 1
            else:
                year = int(year)
        else:
            year = today.year
        # Check the month is not outside bounds, or correct the year
        def month_outside_bounds(month, year):
            if month < 1:
                month = month + 12
                year = year - 1
                month, year = month_outside_bounds(month, year)
            elif month > 12:
                month = month - 12
                year = year + 1
                month, year = month_outside_bounds(month, year)
            return month, year

        month, year = month_outside_bounds(month, year)
        # Day
        if day:
            if day[0] in ('-', '+'):
                daydeltafromfirst = today.day + int(day) - 1
                day = 1
            else:
                daydeltafromfirst = int(day) - 1
                day = 1
        else:
            day = today.day
            daydeltafromfirst = 0
        transactiondate = datetime.date(year, month, day)
        if daydeltafromfirst:
            transactiondate = transactiondate + \
                              datetime.timedelta(days=daydeltafromfirst)
        # Create transaction
        trans = transaction.Transaction(owner_username=username,
                                        description=data.get(
                                            tra, 'description'),
                                        amount=data.get(tra, 'amount'),
                                        currency=currency,
                                        date=transactiondate)
        try:
            trans.original_description = data.get(tra, 'original_description')
        except:
            trans.original_description = data.get(tra, 'description')
        db.session.add(trans)
        # Links to accounts
        for accountdata in data.get(tra, 'accounts').split():
            accountdatatb = accountdata.split(':')
            accountnum = accountdatatb[0]
            if len(accountdatatb) > 1:
                amount = accountdatatb[1]
            else:
                amount = trans.amount
            account = accounts[accountnum]
            accountamount = amount * helpers.rate(username, currency.isocode,
                                                  account.currency.isocode)
            db.session.add(
                transaction.TransactionAccount(transaction=trans,
                                               account=account,
                                               amount=accountamount))
        # Links to categories
        for categorydata in data.get(tra, 'categories').split():
            categorydatatb = categorydata.split(':')
            categorynum = categorydatatb[0]
            if len(categorydatatb) > 1:
                amount = categorydatatb[1]
            else:
                amount = trans.amount
            category = categories[categorynum]
            categoryamount = amount * helpers.rate(username, currency.isocode,
                                                   category.currency.isocode)
            db.session.add(
                transaction.TransactionCategory(
                    transaction=trans,
                    category=category,
                    transaction_amount=amount,
                    category_amount=categoryamount))
    db.session.commit()

    ########## OK, finished
    return 200, 'OK'