Ejemplo n.º 1
0
 def _create(self):
     Expense.create(amount=self._expense.amount,
                    time_creating=get_today_now(),
                    category_id=self._expense.category_id,
                    payment_type=self._expense.payment_type,
                    additional_info=self._expense.additional_info,
                    raw_text=self._expense.raw_text)
Ejemplo n.º 2
0
def test_add_expense(client):
    """ Tests if the add_expense feature works correctly. """

    # Tests GET success
    response = client.get('/add-expense')
    assert response.status_code == 200

    # Tests if HTML is being returned
    assert response.content_type == 'text/html; charset=utf-8'

    # Tests if required elements are present
    titles_headings = [
        '<title>Add Expense - Expenses</title>',
        '<h1 class="m-4">Add Expense</h1>'
    ]
    form_elements = [
        '<label for="name" class="form-label">Expense Name</label>',
        '<label for="categories" class="form-label">Category</label>',
        '<label for="amount" class="form-label">Amount</label>',
        '<label for="date" class="form-label">Date</label>'
    ]
    other_elements = ['navbar', 'footer']
    elements = titles_headings + form_elements + other_elements
    for element in elements:
        assert element.encode() in response.data

    # Records number of existing expenses prior to POST
    expenses_length_before_post = len(Expense.objects())

    # Gets sample category created earlier called 'Test Category' required for POST sample data
    sample_category = Category.objects.get(name='Test Category')

    # Creates sample date object required for POST sample data
    sample_date = datetime.date(2021, 1, 1)

    # Tests POST success by creating sample expense called 'Test Expense'
    sample_data = dict(name='Test Expense',
                       category_id=sample_category.id,
                       amount=50,
                       date=sample_date)
    response = client.post('/add-expense', data=sample_data)
    assert response.status_code == 200

    # Tests if expense was added succesfully or not
    if expenses_length_before_post != len(Expense.objects()):
        new_expense = Expense.objects.get(name='Test Expense')
        assert new_expense.name == 'Test Expense'
        assert new_expense.category_id == sample_category.id
        assert new_expense.amount == 50
        assert new_expense.date == sample_date
        assert b'<strong>Success:</strong> Created new expense &#34;Test Expense&#34;.' in response.data
        expense_elements = [
            '<th>Test Expense</th>', '<th>Test Category</th>',
            '<th>$50.00</th>',
            '<th>{}</th>'.format(sample_date.strftime("%Y-%m-%d"))
        ]
        for element in expense_elements:
            assert element.encode() in response.data
    elif expenses_length_before_post == len(Expense.objects()):
        assert b'<strong>Error:</strong>' in response.data
Ejemplo n.º 3
0
def handle_csv_file(csvfile):
    """
    stores the file information in the database and returns the expenses amount per-month
    in a chronological order
    """

    reader = csv.DictReader(csvfile, delimiter=',')

    # A dictionnary where we are going to collect expenses per month
    expense_per_month = {}
    for row in reader:
        # Category check, get it or add it to the database
        cat = Category.objects.get_or_create(name=row['category'])[0]

        # Employee check, get it or add it to the database
        emp = Employee.objects.get_or_create(
            name=row['employee name'], address=row['employee address'])[0]

        # Extract date
        date = datetime.strptime(row['date'], '%m/%d/%Y')

        # Calculating total expense after tax
        pretax_amount = Decimal(row['pre-tax amount'].replace(',', ''))
        tax_amount = Decimal(row['tax amount'].replace(',', ''))
        after_tax = pretax_amount + tax_amount

        # We will collect the total expenses(after tax) represented by every row in the uploaded file
        # and group them by month in a dictionnary: the keys will be integers that will be generated
        # based on the expense date while the values will be tuples. These tuples will contain a string
        # that represents the month in letters and a decimal that represnts the total expense
        year = date.strftime("%Y")
        month = date.strftime("%m")
        # These keys are generated in a way that will help us later on reorganize the expenses per month
        # chronologically
        key = generate_key(year, month)
        try:
            # Key already exists, retrieving the total to update it
            previous_total = expense_per_month[key][1]
        except KeyError:
            # Key doesn't exist, no total to update
            previous_total = 0
        finally:
            # Generating first element of the tuple
            month_year = date.strftime("%B %Y")
            # Updating the dictionnary
            expense_per_month.update(
                {key: (month_year, previous_total + after_tax)})

        # Creating a new expense and saving it to the database
        expense = Expense(date=date,
                          employee=emp,
                          description=row['expense description'],
                          pretax_amount=pretax_amount,
                          tax_name=row['tax name'],
                          tax_amount=tax_amount,
                          category=cat)
        expense.save()
    # Returning a sorted list of tuples
    return generate_sorted_list(expense_per_month)
Ejemplo n.º 4
0
def add_user_expense_to_event(user, event, expenses):
    for expense in expenses:
        if expense["person_key"] == user.key.urlsafe():
            exp = Expense(parent=user.key, person=user.key, cost=float(expense["cost"]), to=event.payer)
            exp.put()
    
#     expense = Expense(parent=user.key, person=user.key, cost=0)
#     expense.put()
    
    event.expenses.append(exp.key)
    event.put()
Ejemplo n.º 5
0
def get_total_spent(date, next_date):
    """ Get total dollars spent """
    if date is None:
        return Expense.objects().sum('amount')

    amount = 0

    for expense in Expense.objects():
        if expense.date >= date and expense.date <= next_date:
            amount += expense.amount

    return amount
Ejemplo n.º 6
0
def json_add_expense_payment(request, band_id):
    if isInBand(request.user, band_id):
        #current user is in this band
        data = json.loads(request.body)
        desc = data["desc"]
        amount = data["amount"]
        dateTime = data["dateTime"]
        location = data["location"]
        memberList = Member.objects.filter(userName=request.user)
        member = memberList[0]
        band = Band.objects.get(id=band_id)
        expense = Expense(band=band, description=desc, amount=amount, dateTime=dateTime, location=location, addedBy=member)
        expense.save()
        return HttpResponse("success")
    return HttpResponse("failure")
Ejemplo n.º 7
0
    def delete(self, trip_key, expense_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the expense
            expense = Expense.get(expense_key)

            # verify the user is authorized to delete the expense
            authz.deleteExpense(expense)

            # delete the expense
            expense.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError:
            errors.append(
                {"message": "You are not authorized to delete that expense"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete expense"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Ejemplo n.º 8
0
    def update_finance(finances, ftype):
        # Delete any finances which have been removed.
        new_finances = [finance['id'] for finance in finances if finance['id']]
        if ftype == 'revenues':
            entity.revenues = [revenue for revenue in entity.revenues if revenue.id in new_finances]
        elif ftype == 'expenses':
            entity.expenses = [expense for expense in entity.expenses if expense.id in new_finances]

        # Do this or else list comprehensions don't work as expected.
        db.commit()

        # Create or update.
        for finance in finances:
            if finance['id']:
                # Finance exists, update data.
                oldfinance = Finance.query.get(finance['id'])
                if oldfinance.amount != finance['amount']:
                    oldfinance.amount = finance['amount']
                    app.logger.debug('UPDATING ' + ftype + ' AMOUNT: ' + str(oldfinance.amount))
                if oldfinance.year != finance['year']:
                    oldfinance.year = finance['year']
                    app.logger.debug('UPDATING ' + ftype + ' YEAR: ' + str(oldfinance.year))
            else:
                # Finance doesn't exist, create it.
                if ftype is 'revenues':
                    revenue = Revenue(finance['amount'], finance['year'])
                    entity.revenues.append(revenue)
                    app.logger.debug('NEW REVENUE -- ' + str(revenue.year) + ': ' + str(revenue.amount))
                elif ftype is 'expenses':
                    expense = Expense(finance['amount'], finance['year'])
                    entity.expenses.append(expense)
                    app.logger.debug('NEW EXPENSE -- ' + str(expense.year) + ': ' + str(expense.amount))
        db.commit()
Ejemplo n.º 9
0
def get_average_expense_amount(date, next_date):
    """ Get average expense amount """
    if date is None:
        return Expense.objects().average('amount')
    
    total = 0
    num = 0
    for expense in Expense.objects():
        if expense.date >= date and expense.date <= next_date:
            total += expense.amount
            num += 1

    try:
        return total / num
    except ZeroDivisionError:
        return 0
Ejemplo n.º 10
0
def addExpense(**kwargs):
    """ Добавить позицию в таб. Expense """
    db.session.close()
    data = Expense(**kwargs)
    db.session.add(data)
    db.session.commit()
    return 'Add an Expense'
Ejemplo n.º 11
0
    def delete(self, trip_key, expense_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the expense
            expense = Expense.get(expense_key)

            # verify the user is authorized to delete the expense
            authz.deleteExpense(expense)

            # delete the expense
            expense.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError:
            errors.append({"message": "You are not authorized to delete that expense"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete expense"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Ejemplo n.º 12
0
def adhoc_charge():
    if not current_user.isSuperUser:
        abort(401)

    amount = request.json['amount']
    subject = request.json['subject']
    message = request.json['message']

    users = User.query.order_by(User.firstname.asc()).all()
    cost_per_player = float("{0:.2f}".format(float(amount) / float(len(users))))

    """Add expense entry"""
    expense_entry = Expense(amount, cost_per_player, "Deduction_AdHoc", len(users))
    db.session.add(expense_entry)
    db.session.commit()

    email_ids = []
    for user in users:
        email_ids.append(user.email)
        user.balance = float("{0:.2f}".format(user.balance - cost_per_player))

        transaction = Transaction(user.email, cost_per_player, user.balance, "Deduct_AdHoc")
        db.session.add(transaction)
        db.session.commit()

    SendGrid.send_email(email_ids, "*****@*****.**", subject, message)

    """Insert a log"""
    description = 'An AdHoc amount of $' + str(amount) + ' is charged for reason: ' + subject
    log = Log(current_user.email, description)
    db.session.add(log)
    db.session.commit()
    return "Success"
Ejemplo n.º 13
0
    def get(self, trip_key, expense_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # first, verify they have access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append(
                {"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # this is a read of an existing expense
        # instead of directly authorizing the read of an expense, we
        # ensure that the expense is tied to the specified trip
        try:
            # get the expense
            expense = Expense.get(expense_key)

            # ensure the expense belongs to the trip
            if expense.parent_key() != trip.key():
                raise PermissionError("Expense is not tied to that trip")

            # format expense data
            output = GqlEncoder().encode(expense)

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError as e:
            errors.append({"message": e.args})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Ejemplo n.º 14
0
 def __select_groceries_sum_query(self) -> Expense:
     groceries_sum_query = (Expense.select(
         fn.SUM(Expense.amount).alias('sum')).join(Category).join(
             TypeofCategory).where(
                 (TypeofCategory.name == 'Groceries')
                 & (Expense.time_creating.truncate(
                     self._formatter.period_name) == self._period)))
     return groceries_sum_query
Ejemplo n.º 15
0
def api_expense(request, expense_pk=None):
    if expense_pk:
        expense = Expense.objects.get(pk=expense_pk)
        if not expense.created_by == request.user:
            return HttpResponse(status=403)
    else:
        expense = Expense()
        expense.created_by = request.user
    expense.description = request.POST.get('description')
    expense.save()

    if request.is_ajax():
        return HttpResponse(json.dumps({
            'type': 'expense',
            'expense_description': expense.description
        }))
    return HttpResponseRedirect("/%s" % expense.pk)
Ejemplo n.º 16
0
    def get(self, trip_key, expense_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # first, verify they have access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append({"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # this is a read of an existing expense
        # instead of directly authorizing the read of an expense, we
        # ensure that the expense is tied to the specified trip
        try:
            # get the expense
            expense = Expense.get(expense_key)

            # ensure the expense belongs to the trip
            if expense.parent_key() != trip.key():
                raise PermissionError("Expense is not tied to that trip")

            # format expense data
            output = GqlEncoder().encode(expense)

        except db.BadKeyError:
            errors.append({"message": "Invalid expense key"})
        except PermissionError as e:
            errors.append({"message": e.args})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Ejemplo n.º 17
0
 def __select_categories_query(self):
     stat_category_query = (Expense.select(
         fn.SUM(Expense.amount).alias('sum'), Category.name,
         Expense.payment_type).join(Category).where(
             Expense.time_creating.truncate(
                 self._formatter.period_name) == self._period).group_by(
                     Expense.category_id, Category.name,
                     Expense.payment_type).order_by(Expense.category_id))
     return stat_category_query
Ejemplo n.º 18
0
 def createExpense(self, amount, note, date, cat):
     """
     Insert an Expense entry into the db
     """
     expense = Expense(amount=amount, note=note, date=date, category_id=cat)
     self.session.add(expense)
     self.session.flush()
     self.session.commit()
     return expense
Ejemplo n.º 19
0
	def post(self):
		c_per = memcache.get('current_person')
		
		if not c_per:
			return # ERROR! Invalid attempt to post schedules
		if not c_per.schedule:
			return # ERROR! Person don't have an schedule ... probably an invalid attempt
		
		## TODO: Do a nice data validation?? could be JScript too ...
		exp = Expense( belongs = c_per,
	                 name = self.request.get('name'), 
	                 value = self.request.get('cost'),
	                 when = self.request.get('date'),
	                 description = self.request.get('desc') )
		exp.put()		
		memcache.set('current_person',c_per,PERSON_EXPIRE_TIME)
		
		self.redirect('/')
Ejemplo n.º 20
0
def test_delete_expense(client):
    """ Tests if delete_expense feature works correctly. """

    # Records number of existing expenses prior to deleting
    expenses_length_before_delete = len(Expense.objects())

    # Gets sample expense that was edited to 'Test Expense 2'
    sample_expense = Expense.objects.get(name='Test Expense 2')

    # Tests GET success (automatically deletes expense)
    response = client.get('/delete-expense/{}'.format(str(sample_expense.id)))
    assert response.status_code == 200

    # Tests if HTML is being returned
    assert response.content_type == 'text/html; charset=utf-8'

    # Tests if expense was deleted succesfully or not
    assert expenses_length_before_delete != len(Expense.objects())
    assert b'<strong>Success:</strong> Deleted expense &#34;Test Expense 2&#34;.' in response.data
Ejemplo n.º 21
0
def create_pending_expense(db: Collection, expense: Expense,
                           original_msg_id: int, callback_msg_id: int,
                           group_id: int):
    pending = {
        'original_msg_id': original_msg_id,
        'callback_msg_id': callback_msg_id,
        'expense': expense.dict(),
        'group_id': group_id
    }
    result = db.insert_one(pending)
Ejemplo n.º 22
0
 def _select_groceries_sum_with_limit_query(self) -> Expense:
     groceries_monthly_limit_query = (Expense.select(
         fn.SUM(Expense.amount).alias('sum'),
         TypeofCategory.monthly_limit).join(Category).join(
             TypeofCategory).where(
                 (Expense.time_creating.truncate(
                     self._formatter.period_name) == self._period)
                 & (TypeofCategory.monthly_limit.is_null(False))).group_by(
                     TypeofCategory.monthly_limit).tuples())
     return groceries_monthly_limit_query
Ejemplo n.º 23
0
def expense_create_alexa(amount, category):
    user = User.query.filter_by(id=1).first()
    amount = float(amount)
    description = category  # MAKE SURE THAT THIS IS CAPITAL
    print(user, file=sys.stderr)
    new_income_statement = Expense(str(1), amount, description)
    db_session.add(new_income_statement)
    db_session.commit()
    print('Created Expense Statement', file=sys.stderr)
    return '{"success": "200"}'
Ejemplo n.º 24
0
def test_get_total_spent():
    """ Tests if get_total_spent returns the correct total. """

    # Creates sample data that will be used in test
    create_sample_data()

    # Compares return values to sample data
    assert statistics_controller.get_total_spent(
        None, None) == Expense.objects().sum('amount')
    assert statistics_controller.get_total_spent(None, None) == 101
    assert statistics_controller.get_total_spent(datetime.date(
        2021, 1, 1), datetime.date(2021, 2,
                                   1)) == Expense.objects().sum('amount')
    assert statistics_controller.get_total_spent(datetime.date(2021, 1, 1),
                                                 datetime.date(2021, 2,
                                                               1)) == 101

    # Deletes sample data that was used in test
    delete_sample_data()
Ejemplo n.º 25
0
def add_expense():

    if len(Category.objects()) < 1:
        return list_expenses(error='You cannot create an expense until you create at least one category.')

    form = ExpenseForm(request.form)
    if request.method == 'POST':
        if form.validate(): 
            if __get_expense_by_name(form.name.data) != None:
                return render_template('views/expense_form.html', page_name='edit_expense', page_title='Edit Expense', categories=Category.objects(), error='An expense with that name already exists.')

            expense = Expense(name=form.name.data, category_id=form.category_id.data, amount=form.amount.data, date=form.date.data)
            expense.save()

            return list_expenses(success='Created new expense "{}".'.format(form.name.data))
        else:
            return render_template('views/expense_form.html', page_name='add_expense', page_title='Add Expense', categories=Category.objects(), errors=parse_form_errors(form.errors.items()))

    return render_template('views/expense_form.html', page_name='add_expense', page_title='Add Expense', categories=Category.objects())
Ejemplo n.º 26
0
 def __select_detail_query(self):
     expense_detail_query = (Expense.select(
         fn.SUM(Expense.amount).alias('sum'), Category.name,
         Expense.payment_type,
         Expense.additional_info).join(Category).where(
             (Expense.time_creating.truncate(self._formatter.period_name) ==
              self._period)
             & (Category.is_additional_info_needed == True)).group_by(
                 Expense.category_id, Category.name, Expense.payment_type,
                 Expense.additional_info).order_by(Expense.category_id))
     return expense_detail_query
Ejemplo n.º 27
0
def delete_category(category_id):

    if len(Expense.objects()) >= 1:
        if len(Category.objects()) == 1:
            # cant delete last category, make new category first
            return list_categories(error='Cannot delete the last category while there are > 1 expenses.')

        if len(Expense.objects(category_id=category_id)) >= 1:
            # must move expenses to new category or delete all expenses with this category id
            return list_categories(error='Cannot delete this category when other expenses depend on it.')


    category = __get_category(category_id)

    if category == None:
        return no_category_found('Cannot delete, no category found with that ID.')

    category.delete()

    return list_categories(success='Deleted category "{}".'.format(category.name))
Ejemplo n.º 28
0
def run_shuttle_expense():
    if not current_user.isSuperUser:
        abort(401)

    cost = float(request.args.get('cost'))

    if cost <= 0:
        abort(400)

    active_users = User.query.filter(or_(User.isSaturdayAbsent == False, User.isSundayAbsent == False))\
        .order_by(User.firstname.asc())

    if not active_users or active_users.count() < 1:
        abort(404)

    shuttle_cost_per_player = float("{0:.2f}".format(
        float(cost) / float(active_users.count())))
    """Add expense entry"""
    expenseEntry = Expense(cost, shuttle_cost_per_player, "Deduction_Shuttles",
                           active_users.count())
    db.session.add(expenseEntry)
    db.session.commit()
    """Insert a log"""
    description = 'Shuttle expense for $' + str(cost) + ' is run'
    log = Log(current_user.email, description)
    db.session.add(log)
    db.session.commit()

    bodyText = 'Hi everyone,\r\n\nA total of $' + str(cost) + ' is charged for shuttles and it is charged ' + \
               'equally among ' + str(active_users.count()) + ' active players.' + \
               '\r\n\nBalances of players are as follows after deduction:\r\n\n'

    email_ids = []
    for user in active_users:
        user.balance = float("{0:.2f}".format(user.balance -
                                              shuttle_cost_per_player))
        db.session.commit()

        transaction = Transaction(user.email, shuttle_cost_per_player,
                                  user.balance, "Deduct_Shuttle")
        db.session.add(transaction)
        db.session.commit()

        email_ids.append(user.email)
        bodyText += user.firstname + ' ' + user.lastname + ' : ' + '$' + str(
            user.balance) + '\r\n'

    bodyText += '\nThanks\r\nSydney Badminton Group'
    SendGrid.send_email(email_ids, "*****@*****.**",
                        "Badminton: Balances after Shuttles expenses",
                        bodyText)

    return "Success"
Ejemplo n.º 29
0
def json_sell_trade_merch(request, band_id):
    if isInBand(request.user, band_id):
        #current user is in this band
        #the backend will:
        #   deduct stock, add cash to balance, create expense record, add to numSold, add to numTraded
        #get the data from post
        data = json.loads(request.body)
        merchPk = data["merchPk"]
        merchOptionPk = data["merchOptionPk"]
        sellOrTrade = data["sellOrTrade"]
        #get the merch item
        merch = Merch.objects.get(id=merchPk)
        merchOption = MerchOption.objects.get(id=merchOptionPk)
        #deduct from stock
        merchOption.quantity = merchOption.quantity - 1
        #add to numSold or numTraded
        if sellOrTrade == "sell":
            merchOption.numSold = merchOption.numSold + 1
            #create expense record
            band = Band.objects.get(id=band_id)
            timeStamp = data["timeStamp"]
            desc = data["desc"]
            location = data["location"]
            amount = merchOption.price
            member = Member.objects.filter(userName=request.user)
            newExpense = Expense(band=band,description=desc,amount=amount,dateTime=timeStamp,location=location,addedBy=member[0])
            #add to currentBalance
            band.currentBalance = band.currentBalance + amount
            #save everything
            merchOption.save()
            band.save()
            newExpense.save()
        if sellOrTrade == "trade":
            merchOption.numTraded = merchOption.numTraded + 1
            #save everything
            merchOption.save()
        
        return HttpResponse("success")
    return HttpResponse("failure")
Ejemplo n.º 30
0
def get_top_expenses_data(date, next_date):
    """ Get top 10 expenses, sorted by amount spent """
    data = []

    if date is None:
        expenses = Expense.objects().order_by('-amount').limit(10)
    else:
        expenses = []
        num = 1
        for expense in Expense.objects().order_by('-amount'):
            if expense.date >= date and expense.date <= next_date and num <= 10:
                expenses.append(expense)
                num += 1

    for expense in expenses:
        data.append({
            'name': expense.name,
            'amount': expense.amount,
            'date': expense.date
        })

    return data
Ejemplo n.º 31
0
def parse_file(f,breakdown):
    
    # a year/month cross table that stores the totals
    # e.g. : {'2014': { 'January': 1300, 'February':500 }, '2013' : { }}

    for i,line in enumerate(f):
        if i != 0: ## skip header line

            date,category,name,address,description,pretax_amount,tax_name,tax_amount = parse_line(line)
            
            # reformat date into standard YYYY-MM-DD format 
            # this format enables querying the database for time periods and obtaining results sorted by time
            year,month,day = split_date(date)
            std_date = year + '-' + month + '-' + day
            
            # 1. save to memory
            full_amount = float(pretax_amount) + float(tax_amount)
            update_breakdown(breakdown,year,month,full_amount)
            
            #2. save to database
            expense=Expense(
                    date_db = std_date, 
                    date = date,
                    category = category,
                    name = name,
                    address = address,
                    description = description,
                    pretax_amount = pretax_amount,
                    tax_name = tax_name,
                    tax_amount = tax_amount
                    )
            try:
                expense.save()
                duplicates = False
            except:  # IntegrityError as detail:
                duplicates = True      

    return duplicates
Ejemplo n.º 32
0
    def get(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # verify access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append(
                {"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # next, get the list of expenses
        try:
            expenses = Expense.all()
            expenses.ancestor(trip)
            output = GqlEncoder().encode(expenses.fetch(limit=200))
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error listing expenses"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"errors": errors})

        self.response.headers["Content-type"] = "application/json"
        self.response.out.write(output)
Ejemplo n.º 33
0
def get_category_spending_data(date, next_date):
    """ Get number of dollars spent for each category """
    data = []

    categories = Category.objects()

    for category in categories:
        if date is None:
            data.append({
                'name': category.name,
                'total': "{:.2f}".format(Expense.objects(category_id=category.id).sum('amount'))
            })
        else:
            amount = 0
            for expense in Expense.objects():
                if expense.date >= date and expense.date <= next_date and expense.category_id == category.id:
                    amount += expense.amount

            data.append({
                'name': category.name,
                'total': "{:.2f}".format(amount)
            })

    return data
Ejemplo n.º 34
0
async def create_expense(expense_request: ExpenseRequest,
                         db: Session = Depends(get_db)):
    expense = Expense()
    expense.date = expense_request.date
    expense.description = expense_request.description
    expense.currency = expense_request.currency
    expense.amount = expense_request.amount
    db.add(expense)
    db.commit()
    return {'expense created!!'}
Ejemplo n.º 35
0
    def get(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # verify access to the trip
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to read the trip
            authz.readTrip(trip)

        except PermissionError:
            errors.append({"message": "You are not authorized to view that trip"})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # if errors encountered so far, bail
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # next, get the list of expenses
        try:
            expenses = Expense.all()
            expenses.ancestor(trip)
            output = GqlEncoder().encode(expenses.fetch(limit=200))
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error listing expenses"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"errors": errors})

        self.response.headers["Content-type"] = "application/json"
        self.response.out.write(output)
Ejemplo n.º 36
0
    def delete(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to delete the trip
            authz.deleteTrip(trip)

            # delete related expenses
            try:
                expenses = Expense.all()
                expenses.ancestor(trip)
                expenses.fetch(limit=200)
                db.delete(expenses)
            except Exception as e:
                logging.exception(e)
                errors.append({
                    "message":
                    "Unexpected error deleting associated expenses"
                })

            # delete the trip
            trip.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append(
                {"message": "You are not authorized to delete that trip"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Ejemplo n.º 37
0
def create_sample_data():
    """ 
        Creates sample data for testing.
        There should be 11 expenses totaling $101.00. All have the same category and date. 
    """
    
    # Creates a sample category and sample date that can be used to create sample expenses
    sample_category = Category(name='Test Category')
    sample_category.save()
    sample_date = datetime.date(2021, 1, 1)
    
    # Creates 11 sample expenses, last expense created has a lower amount so it can be tested to see if it is excluded in the top ten highest expenses graph
    for i in range(10):
        i += 1
        new_expense = Expense(name='Expense {}'.format(str(i)), category_id=sample_category.id, amount=10, date=sample_date)
        new_expense.save()
    new_expense = Expense(name='Expense 11', category_id=sample_category.id, amount=1, date=sample_date)
    new_expense.save()
Ejemplo n.º 38
0
    def delete(self, trip_key):

        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to delete the trip
            authz.deleteTrip(trip)

            # delete related expenses
            try:
                expenses = Expense.all()
                expenses.ancestor(trip)
                expenses.fetch(limit=200)
                db.delete(expenses)
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error deleting associated expenses"})

            # delete the trip
            trip.delete()

        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except PermissionError:
            errors.append({"message": "You are not authorized to delete that trip"})
        except db.NotSavedError:
            errors.append({"message": "Unable to delete trip"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error deleting trip"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)
Ejemplo n.º 39
0
    def deleteExpense(self, expense):
        """Determines whether the user is allowed to delete an expense"""
        if isinstance(expense, Expense):
            pass
        else:
            expense = Expense.get(expense)
        
        # determine if the user owns the related trip
        try:
            trip = Trip.get(expense.parent_key())
        except db.BadKeyError:
            raise PermissionError('User cannot delete this expense because the trip could not be loaded')
        
        # if yes, they are allowed to delete the expense
        if self.user == trip.owner:
            return
        
        # if they own the expense itself, then they can delete it
        if self.user == expense.creator:
            return

        raise PermissionError('User cannot delete this expense')
Ejemplo n.º 40
0
    def post(self, trip_key):
        errors = []
        output = ""
        user = users.get_current_user()
        authz = Authz(user)
        self.response.headers["Content-type"] = "application/json"

        # check for authorization to create expenses for this trip & verify this
        # is in fact a request to create a new expense
        try:
            # get the trip
            trip = Trip.get(trip_key)

            # verify the user is authorized to create an expense on this trip
            authz.createExpense(trip)

        except PermissionError as e:
            # this permission error could have come from authz or locally
            errors.append({"message": e.args})
        except db.BadKeyError:
            errors.append({"message": "Invalid trip key"})
        except Exception as e:
            logging.exception(e)
            errors.append({"message": "Unexpected error loading trip"})

        # bail if we hit authz errors
        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})
            self.response.out.write(output)
            return

        # having passed authz, let's try creating the expense
        data = ExpenseUnpacker().unpack_post(self.request)

        if data["description"] == "" or data["value"] == "" or data["payer"] == "":
            errors.append({"message": "Description, value, and payer are required."})
        elif len(data["travelers"]) == 0:
            errors.append({"message": "At least one person must be specified as a traveler."})
        else:
            try:
                expense = Expense(
                    parent=trip.key(),
                    creator=user,
                    description=data["description"],
                    value=int(data["value"]),
                    currency="USD",
                )

                # get the expense date
                expense_date = dateparse(data["expense_date"])
                expense.expense_date = expense_date.date()

                # TODO: make sure these travelers are actually on the trip
                expense.travelers = data["travelers"]

                # TODO: ensure the payer is actually a traveler
                expense.payer = data["payer"]

                expense.put()

                output = GqlEncoder().encode(
                    {
                        "id": "%s" % expense.key(),
                        "modify_date": expense.modify_date,
                        "expense_date": expense.expense_date,
                        "value": expense.value,
                    }
                )
            except Exception as e:
                logging.exception(e)
                errors.append({"message": "Unexpected error creating expense"})

        if len(errors) > 0:
            self.response.set_status(400)
            output = json.dumps({"error": errors})

        self.response.out.write(output)