Skip to content

Commit

Permalink
Added new invoice style; removed download invoice as PDF API endpoint.
Browse files Browse the repository at this point in the history
Signed-off-by: Trey <[email protected]>
  • Loading branch information
TreyWW committed Jul 16, 2024
1 parent 706c434 commit 402ee4a
Show file tree
Hide file tree
Showing 19 changed files with 514 additions and 310 deletions.
16 changes: 0 additions & 16 deletions backend/api/invoices/manage.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,22 +32,6 @@ class ErrorResponse:
success: Literal[False] = False


@require_http_methods(["GET"])
def tab_preview_invoice(request: HtmxHttpRequest, invoice_id):
# Redirect if not an HTMX request
if not request.htmx:
return redirect("invoices dashboard") # Maybe should be 404?

prev_invoice = preview_invoice(request, invoice_id)

if prev_invoice.success:
return render(request, "pages/invoices/view/preview_embed.html", prev_invoice.context)

messages.error(request, prev_invoice.message)

return render(request, "base/toasts.html")


def preview_invoice(request: HtmxHttpRequest, invoice_id) -> SuccessResponse | ErrorResponse:
context: dict[str, str | Invoice] = {"type": "preview"}

Expand Down
1 change: 0 additions & 1 deletion backend/api/invoices/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@
path("create_schedule/", schedule.create_schedule, name="create_schedule"),
path("schedules/onetime/<str:schedule_id>/cancel/", schedule.cancel_onetime_schedule, name="schedules onetime cancel"),
path("schedules/onetime/fetch/<str:invoice_id>/", schedule.fetch_onetime_schedules, name="schedules onetime fetch"),
path("manage/<int:invoice_id>/tabs/preview/", manage.tab_preview_invoice, name="tab preview"),
path("", include("backend.api.invoices.reminders.urls")),
]

Expand Down
5 changes: 5 additions & 0 deletions backend/api/public/endpoints/Invoices/download_pdf.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
from datetime import datetime

from django.http import HttpResponse
from drf_yasg import openapi
from drf_yasg.utils import swagger_auto_schema
Expand All @@ -6,6 +8,7 @@
from rest_framework.response import Response

from backend.api.public.decorators import require_scopes
from backend.api.public.helpers.deprecate import deprecated
from backend.api.public.swagger_ui import TEAM_PARAMETER
from backend.api.public.types import APIRequest
from backend.models import Invoice
Expand Down Expand Up @@ -53,8 +56,10 @@
),
),
},
deprecated=True,
)
@api_view(["GET"])
@deprecated(datetime(2024, 7, 16), datetime(2024, 7, 16))
@require_scopes(["invoices:read"])
def download(request: APIRequest, id: str) -> HttpResponse | Response:
try:
Expand Down
13 changes: 12 additions & 1 deletion backend/api/public/helpers/deprecate.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import datetime
import functools
import logging

Expand All @@ -6,7 +7,10 @@
logger = logging.getLogger(__name__)


def deprecated(deprecation_date=None, end_of_life_date=None):
# add type hints for these deprecation dates


def deprecated(deprecation_date: datetime.datetime | None = None, end_of_life_date: datetime.datetime | None = None):
"""
Returns a decorator which informs requester that the decorated endpoint has been deprecated.
"""
Expand All @@ -19,6 +23,13 @@ def wrapper_deprecated(*args, **kwargs):
# do something before handling the request, could e.g. issue a django signal
logger.warning("Deprecated endpoint %s called", func.__name__)

if end_of_life_date and datetime.datetime.now() > end_of_life_date:
return Response(
{"success": False, "message": "This endpoint is no longer available"},
status=410,
headers={"X-Deprecated": "", "X-Deprecation-Date": deprecation_date, "X-End-Of-Life-Date": end_of_life_date},
)

response: Response = func(*args, **kwargs)

# amend the response with deprecation information
Expand Down
10 changes: 7 additions & 3 deletions backend/views/core/invoices/view.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,13 @@ def preview(request: HtmxHttpRequest, invoice_id: str) -> HttpResponse:
messages.error(request, "You don't have access to this invoice")
return redirect("invoices:dashboard")

if response := generate_pdf(invoice, "inline"):
return response
return HttpResponse("Error generating PDF", status=400)
# if response := generate_pdf(invoice, "inline"):
# return response
return render(
request,
"pages/invoices/view/invoice_page.html",
{"invoice": invoice},
)


@login_not_required
Expand Down
28 changes: 27 additions & 1 deletion docs/user-guide/index.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,29 @@
# User Guide

Coming Soon

<div class="grid cards" markdown>

- :material-cursor-pointer:{ .lg .middle } __Set up in 5 minutes__

---

New to MyFinances? Let's go over the basics.

[:octicons-arrow-right-24: Getting started](getting-started/)

- :fontawesome-solid-clock-rotate-left:{ .md .middle } __Release Notes__

---

View our most recent changes. Make sure to view the changelog before upgrading!

[:octicons-arrow-right-24: Changelog](changelog)

<li>
<p>Join our Discord</p>
<hr>
<a target="_blank" href="https://discord.gg/9kKG3SMbAr?utm_source=Discord%20Widget&utm_medium=Connect">
<img src="https://discord.com/api/guilds/1139553863175778367/widget.png?style=banner2"/>
</a>
</li>
</div>
19 changes: 19 additions & 0 deletions docs/user-guide/invoices/sending/download-as-pdf.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
# Download invoice as a PDF

Want to download an invoice as a PDF? Sure thing, let's get started.

First get your invoice created, and head over to the main invoices dashboard. Find your invoice from the list, and click the
three dots on the right - press "Preview"

![Preview dropdown](preview_dropdown.png)

Now you're on the invoice, press "print invoice", or alternatively press
<kbd>CTRL</kbd> + <kbd>P</kbd> or <kbd>CMD</kbd> + <kbd>P</kbd>

![Print invoice](print_invoice.png)
![img.png](img.png)
Once the print dialog appears, select "Save as PDF" as the `destination`, and press `save` at the bottom. Now you have a PDF.
This can be sent to clients manually, or kept as a record!

![Save as PDF](save_as_pdf_destination.png)
![Save](save_button.png)
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/user-guide/invoices/sending/print_dialog.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added docs/user-guide/invoices/sending/save_button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
28 changes: 13 additions & 15 deletions frontend/templates/pages/invoices/dashboard/manage.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
{% block content %}
{% load feature_enabled %}
{% feature_enabled "isInvoiceSchedulingEnabled" as schedule_invoices_enabled %}
<style></style>
<div class="card p-6 shadow-xl bg-base-100 mb-4">
<div class=" text-3xl w-full grid grid-cols-4">
<div hx-boost="true">
Expand All @@ -23,22 +24,19 @@ <h1 class="text-center col-span-2">Invoice #{{ invoice.id }}</h1>
</div>
<div class="card bg-base-100 shadow-xl w-full p-6 flex-col gap-y-4">
<div class="flex flex-wrap gap-y-4">
<button class="btn btn-md btn-outline btn-default grow loading-htmx mr-4"
data-htmx="preview-button"
hx-target="#container"
hx-get="{% url "api:invoices:tab preview" invoice_id=invoice.id %}"
hx-swap="innerHTML"
hx-trigger="load,click,update_invoice from:body,queue:last"
hx-indicator="this">
<a class="btn btn-md btn-outline btn-default grow loading-htmx mr-4"
target="_blank"
rel="noopener noreferrer"
href="{% url 'invoices:preview' invoice_id=invoice.id %}">
<span class="loading-htmx-text">
<i class="fa-solid fa-file-pdf"></i>
<i class="fa-solid fa-up-right-from-square"></i>
Preview Invoice
</span>
<span class="loading loading-spinner loading-htmx-loader"></span>
</button>
</a>
<a href="{% url "invoices:edit" invoice_id=invoice.id %}"
class="btn btn-md btn-outline btn-default grow mr-4">
<i class="fa-solid fa-up-right-from-square"></i>
<i class="fa-solid fa-edit"></i>
Edit Invoice
</a>
<a href="{% url "invoices:manage_access" invoice_id=invoice.id %}"
Expand Down Expand Up @@ -103,9 +101,9 @@ <h1 class="text-center col-span-2">Invoice #{{ invoice.id }}</h1>
</div>
</div>
</div>
<div class="collapse collapse-arrow card bg-base-100 shadow-xl w-full h-screen p-6 flex-row gap-x-4 mt-4">
<input type="checkbox" checked />
<div class="collapse-title text-xl font-medium">Manage Invoice Content</div>
<div id="container" class="collapse-content"></div>
</div>
{# <div class="collapse collapse-arrow card bg-base-100 shadow-xl w-full p-6 flex-row gap-x-4 mt-4">#}
{# <input type="checkbox" checked />#}
{# <div class="collapse-title text-xl font-medium">Manage Invoice Content</div>#}
{# <div id="container" class="collapse-content"></div>#}
{# </div>#}
{% endblock content %}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="navbar fixed bg-base-100 shadow text-base-content print:hidden"
<div class="navbar bg-base-100 shadow text-base-content print:hidden"
id="status_banner">
<div class="navbar-start">
<div class="dropdown">
Expand Down
47 changes: 26 additions & 21 deletions frontend/templates/pages/invoices/view/_client-details.html
Original file line number Diff line number Diff line change
@@ -1,27 +1,32 @@
<header>
Bill to
</header>
{% if c_type == "client" %}
<p class="font-bold text-gray-800">Bill to</p>
{% if invoice.client_to %}
{% if invoice.client_to.is_representative %}{{ invoice.client_to.company }}{% endif %}
<p class="text-gray-500">
{{ invoice.client_to.name|default_if_none:"" }}
-
{{ invoice.client_to.email|default_if_none:"" }}
{% if invoice.client_to.phone_number %}({{ invoice.client_to.phone_number }}){% endif %}
</p>
{% endif %}
{% elif c_type == "manual" %}
<p class="font-bold text-gray-800">Bill to</p>
<p class="text-gray-500">
{% if invoice.client_is_representative %}
<p class="text-lg">{{ invoice.client_company|default_if_none:"" }}</p>
{% if invoice.client_name %}
Represented by <strong>{{ invoice.client_name|default_if_none:"" }}</strong>
{% endif %}
{% if invoice.client_to.is_representative %}
<h1>{{ invoice.client_to.company }}</h1>
<p>
<b>Representative - </b> {{ invoice.client_to.email|default_if_none:"" }}
- {{ invoice.client_to.phone_number|default_if_none:"" }}
</p>
{% else %}
{{ invoice.client_name|default_if_none:"" }}
<br />
{{ invoice.client_address|default_if_none:"" }}
<h1>{{ invoice.client_to.name|default_if_none:"" }}</h1>
<p>
{{ invoice.client_to.email|default_if_none:"" }} - {{ invoice.client_to.phone_number|default_if_none:"" }}
</p>
{% endif %}
</p>
<p class="text-gray-500">{{ invoice.client_email|default_if_none:"" }}</p>
{% endif %}
{% elif c_type == "manual" %}
{% if invoice.client_is_representative %}
<h1>{{ invoice.client_company }}</h1>
<p>
<b>Representative - </b> {{ invoice.client_name|default_if_none:"" }}
<br />
</p>
{% else %}
<h1>{{ invoice.client_name|default_if_none:"" }}</h1>
<p>{{ invoice.client_address|default_if_none:"" }}</p>
{% endif %}
</p>
{% endif %}
Loading

0 comments on commit 402ee4a

Please sign in to comment.