def test_serializes_correctly(self): """ Test that only specific fields are serialized """ spent_by = Person(username="******") spent_for = Person(username="******") budget_group = BudgetGroup() spent_at = datetime(2017, 05, 17) expense = Expense(spent_by=spent_by, spent_for=spent_for, budget_group=budget_group, amount_spent=100, spent_at=spent_at) serializer = ExpenseSerializer(expense) self.assertEqual( { 'id': str(expense.id), 'spent_at': '2017-05-17T00:00:00', 'spent_for': spent_for.id, 'spent_for_purpose': u'', 'spent_by': spent_by.id, 'amount_spent': u'100.00' }, serializer.data)
def new_expense(params, user, group): """ Check if params are valid and create a new expense. Returns a text to send to the user. """ if not params: return 'Necesito que me digas cuanto pagaste y una descripción del gasto.' amount_received, *description = params try: amount = amount_received.replace(',', '.') amount = float(amount) except ValueError: return 'El primer valor que me pasas después del comando tiene que ser el valor de lo '\ 'que pagaste, "{}" no es un número válido.'.format(amount_received) if not description: return 'Necesito que agregues una descripción del gasto.' description = ' '.join(description) expense = Expense(user=user, group=group, description=description, amount=amount) expense.save() return 'Se guardo tu gasto {}'.format(expense)
def create(self, request, **kwargs): parts_to_be_saved = [] try: json_args = request.data exp = Expense( owner=Profile.objects.get(user=request.user), description=json_args['description'], expense_date=datetime.strptime(json_args['expense_date'][:10], "%Y-%m-%d").date() ) for part in json_args['expense_parts']: p = ExpensePart( expense=exp, budget_line_id=part['budget_line_id'], amount=part['amount'] ) parts_to_be_saved.append(p) except KeyError: return Response(status=status.HTTP_400_BAD_REQUEST) exp.save() for p in parts_to_be_saved: p.expense = exp p.save() exp_dict = {'expense': exp.to_dict()} return Response(exp_dict, status=status.HTTP_201_CREATED)
def test_expense_too_small(self): o = Expense( title="Bazooka", amount=0.02, date=f"2020-02-23", ) self.assertRaises(ValidationError, o.full_clean)
def create(request): post_data = request.POST if not post_data: return redirect(new) expense = Expense(name=post_data['name'], source=post_data.get('source', None), amount=post_data['amount'], date=post_data['date']) try: expense.full_clean() except ValidationError as e: for message in e.messages: messages.error(request, message) context = RequestContext( request, { 'expense': expense, 'F_checked': 'checked' if expense.source == "F" else None, 'C_checked': 'checked' if expense.source == "C" else None, 'H_checked': 'checked' if expense.source == "H" else None }) return render(request, 'expenses/new.html', context) else: expense.save() return redirect(index)
def test_expense_too_big(self): o = Expense( title="Boeing 747", amount=212_000_000, date=f"2020-02-23", ) self.assertRaises(ValidationError, o.full_clean)
def new_expense(params, user, group): """ Check if params are valid and create a new expense. Returns a text to send to the user. """ try: data = decode_expense_params(params, group) except ParameterError as e: return str(e) response_text = '' amount = data['amount'] description = data['description'] date = data['dd'] tags = data['tt'] expense = Expense(user=user, group=group, description=description, amount=amount, date=date) if data['exchange_rate']: exchange_rate = data['exchange_rate'] expense.original_currency = exchange_rate.currency expense.original_amount = data['original_amount'] response_text += 'Tu gasto se convirtió a {} usando un tipo de cambio = ${} (cargado el ' \ '{}).\n\n'.format( CURRENCY[exchange_rate.currency], exchange_rate.rate, exchange_rate.date ) expense.save() if tags: for tag in tags: expense.tags.add(tag) response_text += 'Se guardó tu gasto {}'.format(expense) return response_text
def _make_expense_from_line(line): """ Return an :class:`expenses.models.Expense` built from the supplied `line`. Note that the elements found in `line` should be strings. This function takes care of converting them to the expected db types. :param list line: A list of columns containing values to be put into a :class:`expenses.models.Expense` instance. :raise BadCSVFile: If the elements in the `line` can not be properly converted. :return: Non-persisted :class:`expenses.models.Expense` instance. :rtype: :class:`expenses.models.Expense` """ try: return Expense(date=datetime.strptime(line[0], '%m/%d/%Y'), category=line[1], employee_name=line[2], employee_address=line[3], expense_description=line[4], pre_tax_amount=line[5].replace(',', ''), tax_name=line[6], tax_amount=line[7].replace(',', '')) except ValueError: raise BadCSVFile
def execute(self) -> Expense: expense = Expense(title=self.title, amount=self.amount, created_at=self.created_at, tags=self.tags, email=self.email).AddExpense() return expense
def template_run(request, pk): template = get_object_or_404(ExpenseTemplate, pk=pk, user=request.user) expense = Expense(vendor=template.vendor, category=template.category) if "date" in request.GET: expense.date = request.GET["date"] else: expense.date = today_date() if template.type == "count": if not request.GET.get("count"): count = decimal.Decimal(1) else: count = parse_amount_input(request.GET["count"]) if count is None: return HttpResponseBadRequest() expense.amount = round_money(template.amount * count) desc_lines = template.description.strip().split("\n") desc_possibilities = len(desc_lines) desc = desc_lines[0] if count % 1 != 0: # Is decimal, use last possibility desc = desc_lines[desc_possibilities - 1] elif desc_possibilities == 2: # 0 → 1, 1 → anything else (English) desc = desc_lines[int(count != 1)] elif desc_possibilities in {3, 4}: # Polish scheme if count == 1: desc = desc_lines[0] else: # Expression from gettext, simplified desc = desc_lines[1 if (2 <= count % 10 <= 4 and (count % 100 < 10 or count % 100 >= 20)) else 2] expense.description = desc.replace("!count!", str(count)) elif template.type == "description": expense.amount = template.amount expense.description = template.description.replace("!description!", request.GET["description"]) elif template.type == "desc_select": main_desc, *desc_options = template.description.strip().split("\n") desc_id = int(request.GET["desc_id"]) expense.amount = template.amount expense.description = main_desc.strip().replace("!description!", desc_options[desc_id].strip()) elif template.type == "menu": desc_id = int(request.GET["desc_id"]) desc_options = template.description.strip().split("\n") amount_str, desc = desc_options[desc_id].strip().split(" ", 1) expense.amount = parse_amount_input(amount_str.strip()) if expense.amount is None: return HttpResponseBadRequest() expense.description = desc.strip() else: expense.amount = template.amount expense.description = template.description expense.user = request.user expense.save() return HttpResponseRedirect(expense.get_absolute_url())
def new(request): context = RequestContext( request, { 'expense': Expense(), 'F_checked': None, 'C_checked': None, 'H_checked': None }) return render(request, 'expenses/new.html', context)
def execute(self) -> Expense: expense = Expense(id=self.id, title=self.title, amount=self.amount, created_at=self.created_at, tags=self.tags, email=self.email).EditExpense(id=self.id) return expense
def create_expense(self): ex = Expense( description=self.fake.sentence(), date=self.fake.date(), category=random.choice(self.CATEGORY_OPTIONS), owner=User.objects.first(), amount=self.fake.latitude() ) ex.save()
def _create_dummy_expenses(self, user1, user2): now = datetime.datetime.now() few_days_ago = now - datetime.timedelta(days=5) last_month = now - datetime.timedelta(days=35) expense1 = Expense(user=user1, item='Urban Plates', cost=13.34, date_purchased=now, category='Food', subcategory='Eat Out') expense1.save() expense2 = Expense(user=user1, item='Gas', cost=45, date_purchased=few_days_ago, category='Car', subcategory='Gas') expense2.save() expense3 = Expense(user=user1, item='Amazon', cost=64.4, date_purchased=last_month, category='Entertainment', subcategory='One-Timer') expense3.save() expense4 = Expense(user=user2, item='Vons', cost=25, date_purchased=now, category='Food', subcategory='Grocery') expense4.save() expense5 = Expense(user=user2, item='Beer', cost=14, date_purchased=few_days_ago, category='Entertainment', subcategory='Party') expense5.save()
def test_expense(self): o = Expense( title="Mercedes", amount=212_000, date=f"2020-02-23", description="", ) o.full_clean() o.save() self.assertTrue(o.is_expensive())
def bill_quickadd(request): if request.method != "POST": return HttpResponseNotAllowed(["POST"]) quickadd_str = request.POST.get("quickadd") if quickadd_str is None: return HttpResponseBadRequest() category_id, vendor = quickadd_str.split(";", 1) inst = Expense(user=request.user, category_id=category_id, vendor=vendor, is_bill=True) inst.save() return HttpResponseRedirect(reverse("expenses:bill_show", args=[inst.pk]))
def handle(self, n, **options): for i in range(n): o = Expense() o.title = silly.a_thing() o.amount = "{}.{}".format(random.randint(1, 100), random.randint(0, 99)) o.date = silly.datetime().date() o.description = "\n".join( [silly.paragraph(), silly.paragraph(), silly.paragraph()]) o.save()
def test_list_expenses(): """ GIVEN 2 expenses stored in the database WHEN the execute method is called THEN it should return 2 expenses """ Expense(title='New Egdsahggewxpense', amount=12.0, created_at='12/08/1994', tags='daifdsafdsary', email='*****@*****.**').AddExpense() expense = Expense(title='New Expense', amount=12.0, created_at='12/08/1994', tags='dairy', email='*****@*****.**').AddExpense() query = ListExpensesQuery(email=expense.email) assert len(query.execute()) == 2
def test_can_not_spend_without_spent_by(self): """ A spent_by is always required """ spent_for = Person(username="******") budget_group = BudgetGroup() expense = Expense(spent_for=spent_for, budget_group=budget_group, amount_spent=100) self.assertRaises(Person.DoesNotExist, expense.clean)
def test_can_add_expense_from_person_to_group(self): """ A person can spent money for a budget group """ spent_by = Person(username="******") budget_group = BudgetGroup() expense = Expense(spent_by=spent_by, budget_group=budget_group, amount_spent=100) self.assertIsNotNone(expense)
def _populate_expense_table(self, df, users): """DF --> DB""" for i, row in df.iterrows(): for user in users: expense = Expense( user=user, item=row['item'], cost=row['cost'], date_purchased=row['date_purchased'], category=row['category'], subcategory=row['subcategory'] ) expense.save()
def test_can_not_spend_zero_amount(self): """ Creating a negative expense is not possible """ spent_by = Person(username="******") spent_for = Person(username="******") budget_group = BudgetGroup() expense = Expense(spent_by=spent_by, spent_for=spent_for, budget_group=budget_group, amount_spent=0) self.assertRaises(ValidationError, expense.clean)
def test_can_add_expense_from_person_for_person(self): """ A person can spent money for another person """ spent_by = Person(username="******") spent_for = Person(username="******") budget_group = BudgetGroup() expense = Expense(spent_by=spent_by, spent_for=spent_for, budget_group=budget_group, amount_spent=100) self.assertIsNotNone(expense)
def expense_repeat(request, pk): old_expense = get_object_or_404(Expense, pk=pk, user=request.user, is_bill=False) new_expense = Expense( date=today_date(), vendor=old_expense.vendor, category=old_expense.category, amount=old_expense.amount, description=old_expense.description, user=request.user, is_bill=False, ) new_expense.save() messages.add_message(request, messages.SUCCESS, _("Expense has been repeated successfully.")) return HttpResponseRedirect(reverse("expenses:expense_show", args=[new_expense.pk]))
def handle(self, n, *args, **kwargs): Expense.objects.all().delete() for i in range(n): with transaction.atomic(): o = Expense() o.title = silly.a_thing() o.date = silly.datetime().date() o.amount = f"{random.uniform(1, 1000):.2f}" o.comment = "\n".join(silly.paragraph() for i in range(random.randrange(0, 3))) o.save() for j in range(random.randrange(5)): o.notes.create(content="\n".join( silly.paragraph() for i in range(random.randrange(1, 4))))
def test_get_expense_by_id(): """ GIVEN ID of article stored in the database WHEN the execute method is called GetExpenseByIDQuery with id set THEN it should return the expense with the same id """ expense = Expense(title='New Expense', amount=12.0, created_at='12/08/1994', tags='dairy', email='*****@*****.**').AddExpense() query = GetExpenseByIDQuery(id=expense.id, email=expense.email).execute() assert query.title == expense.title assert query.amount == expense.amount assert query.created_at == expense.created_at assert query.tags == expense.tags
def index(): template_names = [] default_fields = None form = ExpensesForm(request.form) default_template_name = '' today = datetime.datetime.now() if request.method == 'POST': if form.validate_on_submit(): for item in form.items.data: entry = Expense(item['expense'], item['cost'], item['due_date'], item['desc'], get_user_id() ) db.session.add(entry) db.session.commit() return redirect(url_for('main.index')) six_months = get_data(db, Expense, session, today) yty_data = dict([(i.due_date.strftime('%Y%m%d'), []) for i in six_months]) for i in six_months: yty_data[i.due_date.strftime('%Y%m%d')].append({'expense': i.expense, 'cost': i.cost, 'expense_type': i.expense_type }) try: default_fields = Template.query.filter_by(user_id=session['user_id'], default=True ).one() default_template_name = default_fields.name default_fields = default_fields.template except Exception as e: print(e) for i in Template.query.filter_by(user_id=session['user_id']).all(): template_names.append(i.name) return render_template('index.html', form=form, expenses=yty_data, name=current_user.username, default_fields=default_fields, template_names=template_names, default_template_name=default_template_name)
def create_random_expense(self): with transaction.atomic(): o = Expense() o.title = silly.a_thing() o.amount = "{}.{}".format(random.randint(1, 100), random.randint(0, 99)) o.date = silly.datetime().date() o.description = "\n".join( [silly.paragraph(), silly.paragraph(), silly.paragraph()]) o.save() for j in range(random.randint(0, 5)): text = "\n".join( [silly.paragraph(), silly.paragraph(), silly.paragraph()]) o.comments.create(content=text)
def test_list_expenses(client): """ GIVEN expenses stored in the database WHEN endpoint /expense-list/ is called THEN it should return list of Expense in json format matching schema """ Expense(title='New Expense', amount=12.0, created_at='12/08/1994', tags='dairy', email='*****@*****.**').AddExpense() data = {'email': '*****@*****.**'} response = client.get( '/expense-list/', data=json.dumps(data), content_type='application/json', ) validate_payload(response.json, 'ExpenseList.json')
def new_expense(params, user, group): """ Check if params are valid and create a new expense. Returns a text to send to the user. """ try: data = decode_expense_params(params, group) except ParameterError as e: return str(e) amount = data['amount'] description = data['description'] date = data['dd'] tags = data['tt'] expense = Expense(user=user, group=group, description=description, amount=amount, date=date) expense.save() if tags: for tag in tags: expense.tags.add(tag) return 'Se guardó tu gasto {}'.format(expense)