From 5f7637d30e8d599982f154c788cadd9894443e05 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Michal=20=C4=8Ciha=C5=99?= Date: Wed, 23 Oct 2024 16:26:35 +0200 Subject: [PATCH] feat: use draft invoices for donation --- weblate_web/invoices/models.py | 29 +++++++++++++++++++++++++--- weblate_web/test-data/fakturace | 2 +- weblate_web/tests.py | 1 + weblate_web/views.py | 34 +++++++++++++++++++++++++-------- 4 files changed, 54 insertions(+), 12 deletions(-) diff --git a/weblate_web/invoices/models.py b/weblate_web/invoices/models.py index 0c20e92dbf..91e94147b8 100644 --- a/weblate_web/invoices/models.py +++ b/weblate_web/invoices/models.py @@ -21,6 +21,7 @@ import datetime from decimal import Decimal from pathlib import Path +from typing import TYPE_CHECKING from django.conf import settings from django.contrib.staticfiles import finders @@ -35,11 +36,20 @@ from weasyprint import CSS, HTML from weasyprint.text.fonts import FontConfiguration +if TYPE_CHECKING: + from weblate_web.payments.models import Payment + INVOICES_URL = "invoices:" STATIC_URL = "static:" TEMPLATES_PATH = Path(__file__).parent / "templates" +def round_decimal(num: Decimal) -> Decimal: + if num % Decimal("0.01"): + return round(num, 3) + return num + + def url_fetcher(url: str) -> dict[str, str | bytes]: path_obj: Path result: dict[str, str | bytes] @@ -211,7 +221,7 @@ def display_total_discount(self) -> str: @cached_property def total_amount_no_vat(self) -> Decimal: - return self.total_items_amount + self.total_discount + return round_decimal(self.total_items_amount + self.total_discount) @property def total_amount_no_vat_czk(self) -> Decimal: @@ -225,7 +235,7 @@ def display_total_amount_no_vat(self) -> str: def total_vat(self) -> Decimal: if not self.vat_rate: return Decimal(0) - return self.total_amount_no_vat * self.vat_rate / 100 + return round_decimal(self.total_amount_no_vat * self.vat_rate / 100) @property def total_vat_czk(self) -> Decimal: @@ -251,6 +261,9 @@ def display_total_amount(self) -> str: def all_items(self) -> models.QuerySet[InvoiceItem]: return self.invoiceitem_set.order_by("id") + def get_description(self) -> str: + return self.all_items[0].description + def render_html(self) -> str: with override("en_GB"): return render_to_string( @@ -322,7 +335,7 @@ def add_amounts(root, in_czk: bool = False): output = etree.SubElement(invoices, "FaktVyd") add_element(output, "Doklad", self.number) add_element(output, "CisRada", self.kind) - add_element(output, "Popis", self.all_items[0].description) + add_element(output, "Popis", self.get_description()) add_element(output, "Vystaveno", self.issue_date.isoformat()) add_element(output, "DatUcPr", self.issue_date.isoformat()) add_element(output, "PlnenoDPH", self.issue_date.isoformat()) @@ -456,6 +469,16 @@ def finalize( ) return invoice + def create_payment(self, recurring: str, extra: dict) -> Payment: + return self.draft_payment_set.create( + amount=self.total_amount, + amount_fixed=True, + description=self.get_description(), + recurring=recurring, + extra=extra, + customer=self.customer, + ) + class InvoiceItem(models.Model): invoice = models.ForeignKey(Invoice, on_delete=models.deletion.CASCADE) diff --git a/weblate_web/test-data/fakturace b/weblate_web/test-data/fakturace index 54b6bee6fd..72914b6b89 160000 --- a/weblate_web/test-data/fakturace +++ b/weblate_web/test-data/fakturace @@ -1 +1 @@ -Subproject commit 54b6bee6fd59e00876e3ba11c4db9187caa3432e +Subproject commit 72914b6b8940d418885d7243e0f2df58c773f937 diff --git a/weblate_web/tests.py b/weblate_web/tests.py index dca2abe552..ee299a191e 100644 --- a/weblate_web/tests.py +++ b/weblate_web/tests.py @@ -685,6 +685,7 @@ def test_donation_workflow_card(self, reward=0): ) self.assertContains(response, "Please provide your billing") payment = Payment.objects.all().get() + self.assertEqual(payment.amount, 1000) self.assertEqual(payment.state, Payment.NEW) customer_url = reverse("payment-customer", kwargs={"pk": payment.uuid}) payment_url = reverse("payment", kwargs={"pk": payment.uuid}) diff --git a/weblate_web/views.py b/weblate_web/views.py index eef161baa1..8752059e97 100644 --- a/weblate_web/views.py +++ b/weblate_web/views.py @@ -21,6 +21,7 @@ import json import random +from decimal import Decimal from typing import TYPE_CHECKING import django.views.defaults @@ -65,6 +66,12 @@ EditNameForm, MethodForm, ) +from weblate_web.invoices.models import ( + Invoice, + InvoiceCategory, + InvoiceKind, + round_decimal, +) from weblate_web.models import ( PAYMENTS_ORIGIN, REWARD_LEVELS, @@ -488,11 +495,6 @@ def get_form_kwargs(self): result["initial"] = self.request.GET return result - def redirect_payment(self, **kwargs): - kwargs["customer"] = get_customer(self.request) - payment = Payment.objects.create(**kwargs) - return redirect(payment.get_payment_url()) - def get_context_data(self, **kwargs): result = super().get_context_data(**kwargs) result["reward_levels"] = REWARD_LEVELS @@ -507,13 +509,29 @@ def form_valid(self, form): tmp = Donation(reward=int(data["reward"] or "0")) with override("en"): description = tmp.get_payment_description() - return self.redirect_payment( - amount=data["amount"], - amount_fixed=True, + customer = get_customer(self.request) + vat_rate = customer.vat_rate + invoice = Invoice.objects.create( + kind=InvoiceKind.DRAFT, + category=InvoiceCategory.DONATE, + customer=customer, + vat_rate=vat_rate, + ) + amount = Decimal(data["amount"]) + if vat_rate: + amount = round_decimal( + amount * Decimal(100) / (Decimal(100) + Decimal(vat_rate)) + ) + invoice.invoiceitem_set.create( description=description, + unit_price=amount, + ) + + payment = invoice.create_payment( recurring=data["recurring"], extra={"reward": data["reward"]}, ) + return redirect(payment.get_payment_url()) @login_required