From fdec63ed55e4b40f08eb8460f5f5fa1ed0190f7d Mon Sep 17 00:00:00 2001 From: Trey <73353716+TreyWW@users.noreply.github.com> Date: Sat, 20 Apr 2024 12:56:08 +0100 Subject: [PATCH] [revamp] Implement price filter receipt (#341) * implemented the filter for total price similar to invoice * Added the edit feature and fixed the bug #328 * added the error handling for receipts * refactor: Removed duplicate step * fix: Fixed modals having their own IDs fix: Default values for non-specified ones fix: Images cant be provided by backend --------- Signed-off-by: Trey <73353716+TreyWW@users.noreply.github.com> Co-authored-by: atanand2 Co-authored-by: atulanand25 <48369355+atulanand25@users.noreply.github.com> --- backend/api/base/modal.py | 19 +++- backend/api/receipts/edit.py | 87 +++++++++++++++++++ backend/api/receipts/fetch.py | 14 +++ backend/api/receipts/urls.py | 7 +- .../templates/modals/receipts_upload.html | 40 ++++++--- .../pages/receipts/_search_results.html | 74 ++++++++++++++-- .../templates/pages/receipts/dashboard.html | 4 +- 7 files changed, 224 insertions(+), 21 deletions(-) create mode 100644 backend/api/receipts/edit.py diff --git a/backend/api/base/modal.py b/backend/api/base/modal.py index 667d1e92..6c1b443a 100644 --- a/backend/api/base/modal.py +++ b/backend/api/base/modal.py @@ -5,7 +5,7 @@ from django.http import HttpResponseBadRequest from django.shortcuts import render -from backend.models import Client +from backend.models import Client, Receipt from backend.models import Invoice from backend.models import QuotaLimit from backend.models import Team @@ -31,6 +31,23 @@ def open_modal(request: HttpRequest, modal_name, context_type=None, context_valu elif context_type == "leave_team": if request.user.teams_joined.filter(id=context_value).exists(): context["team"] = Team.objects.filter(id=context_value).first() + elif context_type == "edit_receipt": + try: + receipt = Receipt.objects.get(pk=context_value) + except Receipt.DoesNotExist: + return render(request, template_name, context) + receipt_date = receipt.date.strftime("%Y-%m-%d") if receipt.date else "" + context = { + "modal_id": f"modal_{receipt.id}_receipts_upload", + "receipt_id": context_value, + "receipt_name": receipt.name, + "receipt_date": receipt_date, + "merchant_store_name": receipt.merchant_store, + "purchase_category": receipt.purchase_category, + "total_price": receipt.total_price, + "has_receipt_image": True if receipt.image else False, + "edit_flag": True, + } elif context_type == "edit_invoice_to": invoice = context_value try: diff --git a/backend/api/receipts/edit.py b/backend/api/receipts/edit.py new file mode 100644 index 00000000..ce02143f --- /dev/null +++ b/backend/api/receipts/edit.py @@ -0,0 +1,87 @@ +from datetime import datetime +from typing import NoReturn +from django.contrib import messages +from django.contrib.auth.decorators import login_required +from django.core.files.uploadedfile import InMemoryUploadedFile +from django.http import HttpRequest, JsonResponse, HttpResponse, HttpResponseBadRequest +from django.shortcuts import render, redirect +from django.views.decorators.http import require_http_methods, require_POST +from backend.models import Receipt + + +@require_http_methods(["POST"]) +@login_required +def edit_receipt(request, receipt_id): + # Fetch the receipt object from the database + try: + receipt = Receipt.objects.get(pk=receipt_id) + + if not receipt.has_access(request.user): + raise Receipt.DoesNotExist + except Receipt.DoesNotExist: + messages.error(request, "Receipt not found") + return render(request, "base/toast.html") + + file: InMemoryUploadedFile | None = request.FILES.get("receipt_image") + date = request.POST.get("receipt_date") + name = request.POST.get("receipt_name") + merchant_store = request.POST.get("merchant_store") + purchase_category = request.POST.get("purchase_category") + total_price = request.POST.get("total_price") + + if not file and not receipt.image: + messages.error(request, "No image found") + return HttpResponseBadRequest("No image found", status=400) + + name = file.name.split(".")[0] if not name else name + + if not name: + messages.error(request, "No name provided, or image doesn't contain a valid name.") + return HttpResponseBadRequest("No name provided, or image doesn't contain a valid name.", status=400) + + if not date: + date = None + + # Compare the values with the existing receipt object + if ( + name != receipt.name + or file != receipt.image + or date != receipt.date + or merchant_store != receipt.merchant_store + or purchase_category != receipt.purchase_category + or total_price != receipt.total_price + ): + + # Update the receipt object + if name: + receipt.name = name + if file: + receipt.image = file + if date: + receipt.date = date + if merchant_store: + receipt.merchant_store = merchant_store + if purchase_category: + receipt.purchase_category = purchase_category + if total_price: + receipt.total_price = total_price + + receipt.save() + + messages.success(request, f"Receipt {receipt.name} (#{receipt.id}) updated successfully.") + else: + messages.info(request, "No changes were made.") + + if request.user.logged_in_as_team: + receipt.organization = request.user.logged_in_as_team + receipts = Receipt.objects.filter(organization=request.user.logged_in_as_team).order_by("-date") + else: + receipt.user = request.user + receipts = Receipt.objects.filter(user=request.user).order_by("-date") + + # Pass the receipt object to the template for rendering + return render( + request, + "pages/receipts/_search_results.html", + {"receipts": receipts}, + ) diff --git a/backend/api/receipts/fetch.py b/backend/api/receipts/fetch.py index 59fd9e22..af88d0ac 100644 --- a/backend/api/receipts/fetch.py +++ b/backend/api/receipts/fetch.py @@ -11,6 +11,16 @@ def fetch_all_receipts(request: HttpRequest): return redirect("receipts dashboard") search_text = request.GET.get("search") + selected_filters = request.GET.get("filter") + + # Define previous filters as a dictionary + previous_filters = { + "amount": { + "20": True if request.GET.get("amount_20+") else False, + "50": True if request.GET.get("amount_50+") else False, + "100": True if request.GET.get("amount_100+") else False, + }, + } results = Receipt.objects.order_by("-date") if request.user.logged_in_as_team: @@ -20,6 +30,10 @@ def fetch_all_receipts(request: HttpRequest): if search_text: results = results.filter(Q(name__icontains=search_text) | Q(date__icontains=search_text)).order_by("-date") + elif selected_filters: + context.update({"selected_filters": [selected_filters]}) + results = results.filter(total_price__gte=selected_filters).order_by("-date") context.update({"receipts": results}) + context["all_filters"] = {item: [i for i, _ in dictio.items()] for item, dictio in previous_filters.items()} return render(request, "pages/receipts/_search_results.html", context) diff --git a/backend/api/receipts/urls.py b/backend/api/receipts/urls.py index 8ffc54df..499b4164 100644 --- a/backend/api/receipts/urls.py +++ b/backend/api/receipts/urls.py @@ -1,5 +1,5 @@ from django.urls import path -from . import delete, new, fetch, download +from . import delete, new, fetch, download, edit urlpatterns = [ path( @@ -12,6 +12,11 @@ new.receipt_create, name="new", ), + path( + "edit//", + edit.edit_receipt, + name="edit", + ), path( "fetch/", fetch.fetch_all_receipts, diff --git a/frontend/templates/modals/receipts_upload.html b/frontend/templates/modals/receipts_upload.html index fcd087d0..3bb77321 100644 --- a/frontend/templates/modals/receipts_upload.html +++ b/frontend/templates/modals/receipts_upload.html @@ -1,8 +1,8 @@ -{% component_block "modal" id="modal_receipts_upload" start_open="true" title="Upload Receipt" %} +{% component_block "modal" id=modal_id start_open="true" title="Upload Receipt" %} {% fill "content" %}