Changes to payment models #32
|
@ -74,6 +74,8 @@ migrate = "./src/manage.py migrate"
|
|||
makemigrations = "./src/manage.py makemigrations"
|
||||
createsuperuser = "./src/manage.py createsuperuser"
|
||||
shell = "./src/manage.py shell"
|
||||
# You need to install Stripe CLI from here to run this: https://github.com/stripe/stripe-cli/releases
|
||||
stripe_cli = "stripe listen --forward-to 0.0.0.0:8000/order/stripe/webhook/"
|
||||
|
||||
[tool.pytest.ini_options]
|
||||
DJANGO_SETTINGS_MODULE="tests.settings"
|
||||
|
|
|
@ -0,0 +1,21 @@
|
|||
# Generated by Django 5.1b1 on 2024-07-31 22:02
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
|
||||
dependencies = [
|
||||
('accounting', '0009_alter_orderproduct_order_alter_orderproduct_product'),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name='orderproduct',
|
||||
options={'verbose_name': 'ordered product', 'verbose_name_plural': 'ordered products'},
|
||||
),
|
||||
migrations.RemoveField(
|
||||
model_name='payment',
|
||||
name='stripe_charge_id',
|
||||
),
|
||||
]
|
|
@ -163,8 +163,6 @@ class Payment(CreatedModifiedAbstract):
|
|||
payment_type = models.ForeignKey("PaymentType", on_delete=models.PROTECT)
|
||||
external_transaction_id = models.CharField(max_length=255, default="", blank=True)
|
||||
|
||||
stripe_charge_id = models.CharField(max_length=255, default="", blank=True)
|
||||
|
||||
class Meta:
|
||||
verbose_name = _("payment")
|
||||
verbose_name_plural = _("payments")
|
||||
|
|
|
@ -30,7 +30,7 @@ def mark_order_paid(sender: models.Payment, instance: models.Payment, **kwargs:
|
|||
instance.order.save()
|
||||
|
||||
|
||||
@receiver(post_save, sender=models.Payment)
|
||||
@receiver(post_save, sender=models.Order)
|
||||
def activate_membership(sender: models.Order, instance: models.Order, **kwargs: dict) -> None: # noqa: ARG001
|
||||
"""Mark a membership as activated when its order is marked as paid."""
|
||||
if instance.is_paid:
|
||||
|
|
|
@ -40,9 +40,10 @@
|
|||
|
||||
<h2>{% trans "Total price" %}: {{ order.total_with_vat }}</h2>
|
||||
|
||||
{% if not order.is_paid %}
|
||||
<p>
|
||||
<a href="{% url "order:pay" order_id=order.pk %}" class="button">{% trans "Pay now" %}</a>
|
||||
</p>
|
||||
|
||||
{% endif %}
|
||||
</div>
|
||||
{% endblock %}
|
||||
|
|
|
@ -7,11 +7,13 @@ from django.core.mail import send_mail
|
|||
from django.db import transaction
|
||||
from django.http import HttpRequest
|
||||
from django.http import HttpResponse
|
||||
from django.shortcuts import get_object_or_404
|
||||
from django.shortcuts import redirect
|
||||
from django.shortcuts import render
|
||||
from django.urls import reverse
|
||||
from django.views.decorators.csrf import csrf_exempt
|
||||
from django_view_decorator import namespaced_decorator_factory
|
||||
from djmoney.money import Money
|
||||
|
||||
from . import models
|
||||
|
||||
|
@ -52,6 +54,8 @@ def order_pay(request: HttpRequest, order_id: int) -> HttpResponse:
|
|||
order = models.Order.objects.get(pk=order_id, member=user)
|
||||
current_site = Site.objects.get_current(request)
|
||||
base_domain = f"https://{current_site.domain}"
|
||||
if settings.DEBUG:
|
||||
f"http://{current_site.domain}"
|
||||
|
||||
try:
|
||||
line_items = []
|
||||
|
@ -70,6 +74,7 @@ def order_pay(request: HttpRequest, order_id: int) -> HttpResponse:
|
|||
)
|
||||
checkout_session = stripe.checkout.Session.create(
|
||||
line_items=line_items,
|
||||
metadata={"order_id": order.id},
|
||||
mode="payment",
|
||||
success_url=base_domain + reverse("order:success", kwargs={"order_id": order.id}),
|
||||
cancel_url=base_domain + "/cancel",
|
||||
|
@ -132,12 +137,12 @@ def cancel(request: HttpRequest, order_id: int) -> HttpResponse:
|
|||
)
|
||||
|
||||
|
||||
@csrf_exempt
|
||||
@transaction.atomic
|
||||
@order_view(
|
||||
paths="stripe/webhook/",
|
||||
name="webhook",
|
||||
login_required=True,
|
||||
)
|
||||
@csrf_exempt
|
||||
def stripe_webhook(request: HttpRequest) -> HttpResponse:
|
||||
"""Handle Stripe webhook.
|
||||
|
||||
|
@ -157,7 +162,16 @@ def stripe_webhook(request: HttpRequest) -> HttpResponse:
|
|||
return HttpResponse(status=400)
|
||||
|
||||
if event["type"] == "checkout.session.completed" or event["type"] == "checkout.session.async_payment_succeeded":
|
||||
# TODO: Implement the payment
|
||||
pass
|
||||
# Order is marked paid via signals, Membership is activated via signals.
|
||||
order_id = event["data"]["object"]["metadata"]["order_id"]
|
||||
order = get_object_or_404(models.Order, pk=order_id)
|
||||
if not models.Payment.objects.filter(order=order).exists():
|
||||
models.Payment.objects.create(
|
||||
order=order,
|
||||
amount=Money(event["data"]["object"]["amount_total"], event["data"]["object"]["currency"]),
|
||||
description="Paid via Stripe",
|
||||
payment_type=models.PaymentType.objects.get_or_create(name="Stripe")[0],
|
||||
external_transaction_id=event["id"],
|
||||
)
|
||||
|
||||
return HttpResponse(status=200)
|
||||
|
|
|
@ -66,7 +66,7 @@ def ensure_membership_type_exists(
|
|||
# Get the default account of the member. We don't really know what to do if a person owns multiple accounts.
|
||||
account, __ = Account.objects.get_or_create(owner=member)
|
||||
# Create an Order for the products in the membership
|
||||
order = Order.objects.create(member=member, account=account)
|
||||
order = Order.objects.create(member=member, account=account, description=membership_type.name)
|
||||
# Add stuff to the order
|
||||
for product in membership_type.products.all():
|
||||
OrderProduct.objects.create(order=order, product=product, price=product.price, vat=product.vat)
|
||||
|
|
Loading…
Reference in a new issue