def update(self, accountid): account = self.__own_account(accountid) if not account: self.notfound( 'Nonexistent account cannot be modified (or you do not own it)') if 'name' in self.args: account.name = self.args['name'] if 'currency' in self.args: # Do not update currency if account has transactions if not models.TransactionAccount.query.filter( models.TransactionAccount.account == account ).count(): 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: account.currency = currency if 'start_balance' in self.args: account.start_balance = Decimal(self.args['start_balance']) self.add_to_response('totalbalance') db.session.commit() return account.as_dict(self.username)
def __own_preference(self, preferencename): return models.UserPreference.query.filter( db.and_( models.UserPreference.user_username == self.username, models.UserPreference.name == preferencename ) ).first()
def list(self): categories = models.Category.query.order_by( models.Category.name).options( db.joinedload(models.Category.currency)).filter( db.and_(models.Category.owner_username == self.username, models.Category.parent_id == None)).all() return [c.as_dict(self.username) for c in categories]
def __search(self, substring): """Search on parts of the users name or on exact email address""" if len(substring) < 3: self.badrequest('Please give at least 3 characters') if '@' in substring: corresponding_rows = models.User.query.join( models.UserEmail ).filter( models.UserEmail.email_address == substring, models.UserEmail.confirmation == 'OK' ) else: substring=u'%{0}%'.format(substring) corresponding_rows = models.User.query.filter( db.and_( models.User.username != self.username, db.or_( models.User.username.like(substring), models.User.first_name.like(substring), models.User.last_name.like(substring), ) ) ) return [u.as_dict() for u in corresponding_rows.all()]
def create(self): if not ( 'currency' in self.args and 'name' in self.args and 'start_balance' in self.args ): self.badrequest( "Please provide the account name, currency and start balance") 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 not currency: self.badrequest("This currency does not exist") name = self.args['name'] start_balance = self.args['start_balance'] a = models.Account( name=name, currency=currency, start_balance=start_balance ) ao = models.AccountOwner(account=a, owner_username=self.username) db.session.add_all((a, ao)) db.session.commit() self.add_to_response('totalbalance') return a.as_dict(self.username)
def create(self): if not 'username' in self.args: self.badrequest("Please provide the contact username") if self.username in config.DEMO_ACCOUNTS: self.badrequest("Cannot add contacts to demo accounts") # Verify the contact exists contactuser = models.User.query.filter( models.User.username == self.args['username'] ).first() if not contactuser: self.notfound('This user does not exist') # Verify the user doesn't already have this contact testcontact = models.UserContact.query.filter( db.and_( models.UserContact.user_username == self.username, models.UserContact.contact_username == self.args['username'] ) ).first() if testcontact: self.badrequest("This contact already exists") contact = models.UserContact( user_username=self.username, contact=contactuser, comment=self.args.get('comment', '') ) db.session.add(contact) db.session.commit() return contact.as_dict()
def create(self): if not ('currency' in self.args and 'name' in self.args): self.badrequest("Please provide category name and currency") if 'parent' in self.args: parent = self.__own_category(self.args['parent']) if not parent: self.badrequest("This parent category does not exist") else: parent = None 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 not currency: self.badrequest("This currency does not exist") category = models.Category( owner_username=self.username, parent=parent, currency=currency, name=self.args['name'] ) db.session.add(category) db.session.commit() return category.as_dict(self.username)
def __own_currency(self, isocode): return models.Currency.query.filter( db.and_( models.Currency.isocode == isocode, db.or_( models.Currency.owner_username == self.username, models.Currency.owner_username == None, )))
def __own_account(self, accountid): return models.Account.query.options( db.joinedload(models.Account.currency) ).join(models.AccountOwner).filter( db.and_( models.AccountOwner.owner_username == self.username, models.Account.id == accountid ) ).first()
def __own_category(self, categoryid): return models.Category.query.options( db.joinedload(models.Category.currency) ).filter( db.and_( models.Category.owner_username == self.username, models.Category.id == categoryid ) ).first()
def read(self, username): contact = models.UserContact.query.filter( db.and_( models.UserContact.user_username == self.username, models.UserContact.contact_username == self.args['username'] ) ).first() if not contact: self.notfound('This contact does not exist') return contact.as_dict()
def __own_currency(self, isocode): return models.Currency.query.filter( db.and_( models.Currency.isocode == isocode, db.or_( models.Currency.owner_username == self.username, models.Currency.owner_username == None, ) ) )
def categoriesbalance(username, categoryid): category = models.Category.query.filter( db.and_(models.Category.owner_username == username, models.Category.id == categoryid)).first() balances = category.balance(username) balances['id'] = categoryid result = [balances] # Also return parent category/ies balance(s) if category.parent_id: result.extend(categoriesbalance(username, category.parent_id)) return result
def accountbalance(username, accountid): account = models.Account.query.join(models.AccountOwner).filter( db.and_(models.AccountOwner.owner_username == username, models.Account.id == accountid)).first() balances = account.balance(username) return { 'id': accountid, 'balance': balances[0], 'balance_preferred': balances[1], 'transactions_count': account.transactions_count() }
def delete(self, username): contact = models.UserContact.query.filter( db.and_( models.UserContact.user_username == self.username, models.UserContact.contact_username == username ) ).first() if not contact: self.notfound('Nonexistent contact cannot be deleted') db.session.delete(contact) db.session.commit()
def __own_transaction(self, transactionid): return models.Transaction.query.options( db.joinedload(models.Transaction.currency), db.joinedload(models.Transaction.transaction_accounts), db.joinedload(models.Transaction.transaction_categories) ).filter( db.and_( models.Transaction.owner_username == self.username, models.Transaction.id == transactionid ) ).first()
def list(self): categories = models.Category.query.order_by( models.Category.name ).options( db.joinedload(models.Category.currency) ).filter( db.and_( models.Category.owner_username == self.username, models.Category.parent_id == None ) ).all() return [c.as_dict(self.username) for c in categories]
def rate(username, fromisocode, toisocode): if fromisocode == toisocode: return 1 # Request the currencies fromcurrency = core.Currency.query.filter( db.and_( core.Currency.isocode == fromisocode, db.or_(core.Currency.owner_username == username, core.Currency.owner_username == None), ) ).first() tocurrency = core.Currency.query.filter( db.and_( core.Currency.isocode == toisocode, db.or_(core.Currency.owner_username == username, core.Currency.owner_username == None), ) ).first() if not fromcurrency or not tocurrency: return None # Both currencies are globally defined if (fromcurrency.rate is None) and (tocurrency.rate is None): return exchangerate.getrate(fromcurrency.isocode, tocurrency.isocode) # Both currencies are user-defined elif (fromcurrency.rate is not None) and (tocurrency.rate is not None): return tocurrency.rate / fromcurrency.rate # Mixed user-defined / globally defined rates else: preferred_isocode = core.User.query.filter(core.User.username == username).one().preferred_currency.isocode # From a user-defined currency to a globally defined currency if (fromcurrency.rate is not None) and (tocurrency.rate is None): target_rate = exchangerate.getrate(preferred_isocode, tocurrency.isocode) if fromcurrency.rate == 0: return 0 return target_rate / fromcurrency.rate if (fromcurrency.rate is None) and (tocurrency.rate is not None): source_rate = exchangerate.getrate(preferred_isocode, fromcurrency.isocode) if tocurrency.rate == 0: return 0 return tocurrency.rate / source_rate
def categoriesbalance(username, categoryid): category = models.Category.query.filter( db.and_( models.Category.owner_username == username, models.Category.id == categoryid ) ).first() balances = category.balance(username) balances['id'] = categoryid result = [ balances ] # Also return parent category/ies balance(s) if category.parent_id: result.extend(categoriesbalance(username, category.parent_id)) return result
def update(self, username): contact = models.UserContact.query.filter( db.and_( models.UserContact.user_username == self.username, models.UserContact.contact_username == self.args['username'] ) ).first() if not contact: self.notfound('Nonexistent contact cannot be modified') # Only the comment can be updated if 'comment' in self.args: contact.comment = self.args['comment'] db.session.commit() return contact.as_dict()
def accountbalance(username, accountid): account = models.Account.query.join(models.AccountOwner).filter( db.and_( models.AccountOwner.owner_username == username, models.Account.id == accountid ) ).first() balances = account.balance(username) return { 'id': accountid, 'balance': balances[0], 'balance_preferred': balances[1], 'transactions_count': account.transactions_count() }
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)
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)
def create(self): if not ('currency' in self.args and 'name' in self.args): self.badrequest("Please provide category name and currency") if 'parent' in self.args: parent = self.__own_category(self.args['parent']) if not parent: self.badrequest("This parent category does not exist") else: parent = None 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 not currency: self.badrequest("This currency does not exist") category = models.Category(owner_username=self.username, parent=parent, currency=currency, name=self.args['name']) db.session.add(category) db.session.commit() return category.as_dict(self.username)
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
def update(self, transactionid): transaction = self.__own_transaction(transactionid) if not transaction: self.notfound( 'Nonexistent transaction cannot be modified (or you do not own it)') # First, modifications on the Transaction object itself if 'description' in self.args: desc = self.args['description'] if desc.strip() == '': transaction.description = transaction.original_description else: transaction.description = desc if 'amount' in self.args: transaction.amount = self.args['amount'] 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: transaction.currency = currency if 'date' in self.args: date = helpers.date_from_string(self.args['date']) if date: transaction.date = date # Next, update accounts if 'accounts' in self.args: existing_accounts = dict([ta.as_tuple() for ta in transaction.transaction_accounts]) new_accounts_data = json.loads(self.args['accounts']) for account_data in new_accounts_data: if 'amount' in account_data and 'account' in account_data: amount = account_data['amount'] accountid = account_data['account'] if accountid in existing_accounts.keys(): # Account already linked... if existing_accounts[accountid] != amount: # ...but the amount is different ta = models.TransactionAccount.query.filter(db.and_( models.TransactionAccount.transaction == transaction, models.TransactionAccount.account_id == accountid )).one() ta.amount = amount ta.verified = False self.add_to_response('accountbalance', accountid) existing_accounts.pop(accountid) else: # Account is not already linked # Verify the account is owned by the user accountobject = models.Account.query.options( db.joinedload(models.Account.account_owners) ).filter( db.and_( models.Account.id == accountid, models.AccountOwner.owner_username == self.username ) ).first() if accountobject: ta = models.TransactionAccount( transaction = transaction, account = accountobject, amount = amount, verified = False ) self.add_to_response('accountbalance', accountid) db.session.add(ta) # All accounts to keep have been poped out from "existing_accounts" # Delete all links remaining from this transaction to accounts for accountid in existing_accounts.keys(): ta = models.TransactionAccount.query.filter(db.and_( models.TransactionAccount.transaction == transaction, models.TransactionAccount.account_id == accountid )).one() self.add_to_response('accountbalance', accountid) db.session.delete(ta) self.add_to_response('totalbalance') # Then, update categories if 'categories' in self.args: existing_categories = dict([tc.as_tuple() for tc in transaction.transaction_categories]) new_categories_data = json.loads(self.args['categories']) for category_data in new_categories_data: if 'transaction_amount' in category_data and \ 'category_amount' in category_data and \ 'category' in category_data: transaction_amount = category_data['transaction_amount'] category_amount = category_data['category_amount'] categoryid = category_data['category'] if categoryid in existing_categories.keys(): # Category already linked... if existing_categories[categoryid]['category_amount'] \ != category_amount: # ...but the amount is different tc = models.TransactionCategory.query.filter(db.and_( models.TransactionCategory.transaction == transaction, models.TransactionCategory.category_id == categoryid )).one() tc.transaction_amount = transaction_amount tc.category_amount = category_amount tc.verified = False self.add_to_response('categoriesbalance', categoryid) existing_categories.pop(categoryid) else: # Category is not already linked # Verify the category is owned by the user categoryobject = models.Category.query.filter( db.and_( models.Category.id == categoryid, models.Category.owner_username == self.username ) ).first() if categoryobject: tc = models.TransactionCategory( transaction = transaction, category = categoryobject, transaction_amount = transaction_amount, category_amount = category_amount ) self.add_to_response('categoriesbalance', categoryid) db.session.add(tc) # All categories to keep have been poped out from # "existing_categories" # Delete all links remaining from this transaction to categories for categoryid in existing_categories.keys(): tc = models.TransactionCategory.query.filter(db.and_( models.TransactionCategory.transaction == transaction, models.TransactionCategory.category_id == categoryid )).one() self.add_to_response('categoriesbalance', categoryid) db.session.delete(tc) db.session.commit() return transaction.as_dict(self.username)
def __filter(self, filter): filters = [ models.Transaction.owner_username == self.username, ] limit = 100 after = False for part in filter.items(): if part[0] in filter_functions: filters.extend( filter_functions[part[0]](part[1]) ) elif part[0] == 'limit': try: limit = min(int(part[1]), 100) except: pass elif part[0] == 'after': try: after = int(part[1]) except: pass if after: # Get offset of the "from" transaction # XXX: Is there a more efficient way to do so ? all_transactions = db.session.query(models.Transaction.id).order_by( db.desc(models.Transaction.date) ).filter( db.and_( *filters ) ) all_ids = [t.id for t in all_transactions] try: offset = all_ids.index(after) + 1 except: offset = 0 transactions = models.Transaction.query.options( db.joinedload(models.Transaction.currency), db.joinedload(models.Transaction.transaction_accounts), db.joinedload(models.Transaction.transaction_categories) ).order_by( db.desc(models.Transaction.date) ).filter( db.and_( *filters ) ).offset(offset).limit(limit) return [t.as_dict(self.username) for t in transactions] else: transactions = models.Transaction.query.options( db.joinedload(models.Transaction.currency), db.joinedload(models.Transaction.transaction_accounts), db.joinedload(models.Transaction.transaction_categories) ).order_by( db.desc(models.Transaction.date) ).filter( db.and_( *filters ) ).limit(limit) return [t.as_dict(self.username) for t in transactions]
def update(self, username): if username == 'me' or username == self.username: # A user can only modify his own information user = models.User.query.options( db.joinedload(models.User.emails) ).filter( models.User.username == self.username ).one() if 'first_name' in self.args: user.first_name = self.args['first_name'] if 'last_name' in self.args: user.last_name = self.args['last_name'] if 'password' in self.args and \ username not in config.DEMO_ACCOUNTS: if 'currentpassword' in self.args and \ authentication.authenticate( username, self.args['currentpassword'], False ): if len(self.args['password']) < 8: self.badrequest( 'Password should be at least 8 characters long') user.passhash = sha512_crypt.encrypt( self.args['password'], rounds=config.PASSWORD_SALT_COMPLEXITY ) else: self.badrequest( "Please provide the correct current password") if 'preferred_currency' in self.args: currency = models.Currency.query.filter( db.and_( models.Currency.isocode == self.args['preferred_currency'], models.Currency.owner_username == None, ) ).first() if currency: # When preferred currency is changed, all owner's # currencies rates must be changed # XXX Debts amounts should also be changed... when debts will be implemented multiplier = user.preferred_currency multiplier = exchangerate.getrate( user.preferred_currency.isocode, currency.isocode ) for c in models.Currency.query.filter( models.Currency.owner_username == self.username ): c.rate = c.rate * multiplier user.preferred_currency = currency self.add_to_response('totalbalance') if 'emails' in self.args: emails = json.loads(self.args['emails']) previous_emails = [] previous_notifications = [] for address in models.UserEmail.query.filter( models.UserEmail.user_username == self.username): previous_emails.append(address.email_address) if address.notification: previous_notifications.append(address.email_address) if type(emails) == type({}): if 'add' in emails and \ type(emails['add']) == type([]) and \ username not in config.DEMO_ACCOUNTS: for address in emails['add']: # TODO Verify there is a "@" in the email address if address not in previous_emails: # Use random hash for email confirmation # Email confirmation is done outside of OSPFM # Another process must read the database and # send confirmation emails randomhash = os.urandom(8).encode('hex') db.session.add( models.UserEmail( user_username = self.username, email_address = address, confirmation = randomhash ) ) if 'remove' in emails and type(emails['remove'])==type([]): for address in emails['remove']: if address in previous_emails: db.session.delete( models.UserEmail.query.filter( db.and_( models.UserEmail.user_username == self.username, models.UserEmail.email_address == address ) ).first() ) if 'enablenotifications' in emails and \ type(emails['enablenotifications']) == type([]): for address in emails['enablenotifications']: if address not in previous_notifications: models.UserEmail.query.filter( db.and_( models.UserEmail.user_username == self.username, models.UserEmail.email_address == address ) ).first().notification = True if 'disablenotifications' in emails and \ type(emails['disablenotifications']) == type([]): for address in emails['disablenotifications']: if address in previous_notifications: models.UserEmail.query.filter( db.and_( models.UserEmail.user_username == self.username, models.UserEmail.email_address == address ) ).first().notification = False db.session.commit() return self.read(username) else: self.forbidden('The only user you can modify is yourself')
def create(self): if not ( 'currency' in self.args and \ 'date' in self.args and \ 'description' in self.args and \ 'amount' in self.args ): self.badrequest( "Please provide transaction description, currency, amount and date") # First, create the transaction object 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 not currency: self.badrequest("This currency does not exist") date = helpers.date_from_string(self.args['date']) if not date: self.badrequest("This date cannot be understood") description = self.args['description'] if 'original_description' in self.args: original_description = self.args['original_description'] else: original_description = description transaction = models.Transaction( owner_username = self.username, description = description, original_description = original_description, amount = self.args['amount'], currency = currency, date = date ) db.session.add(transaction) # Next, create the links from the transaction to its accounts if 'accounts' in self.args: accounts = json.loads(self.args['accounts']) for accountdata in accounts: transaction_accounts = [] if 'amount' in accountdata: # If no amount is specified, do not associate the account accountobject = models.Account.query.options( db.joinedload(models.Account.account_owners) ).filter( db.and_( models.Account.id == accountdata['account'], models.AccountOwner.owner_username == self.username, ) ).first() if accountobject: ta = models.TransactionAccount( transaction = transaction, account = accountobject, amount = accountdata['amount'], verified = False ) db.session.add(ta) self.add_to_response('accountbalance', accountdata['account']) self.add_to_response('totalbalance') # Next, create the links from the transaction to its categories if 'categories' in self.args: categories = json.loads(self.args['categories']) for categorydata in categories: transaction_categories = [] if 'transaction_amount' in categorydata and \ 'category_amount' in categorydata: # If no amount is specified, do not associate the category categoryobject = models.Category.query.options( db.joinedload(models.Category.currency) ).filter( db.and_( models.Category.id == categorydata['category'], models.Category.owner_username == self.username, ) ).first() if categoryobject: tc = models.TransactionCategory( transaction = transaction, category = categoryobject, transaction_amount = categorydata['transaction_amount'], category_amount = categorydata['category_amount'] ) db.session.add(tc) self.add_to_response('categoriesbalance', categorydata['category']) # Commit everything... db.session.commit() return transaction.as_dict(self.username)
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'
def __own_category(self, categoryid): return models.Category.query.options( db.joinedload(models.Category.currency)).filter( db.and_(models.Category.owner_username == self.username, models.Category.id == categoryid)).first()
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'
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