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)
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 "Test Expense".' 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
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)
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()
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
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")
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)
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()
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
def addExpense(**kwargs): """ Добавить позицию в таб. Expense """ db.session.close() data = Expense(**kwargs) db.session.add(data) db.session.commit() return 'Add an Expense'
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)
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"
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)
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
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)
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)
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
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
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('/')
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 "Test Expense 2".' in response.data
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)
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
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"}'
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()
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())
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
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))
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"
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")
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
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
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)
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
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!!'}
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)
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)
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()
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)
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')
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)