Skip to content

Commit

Permalink
Merge pull request #24 from Naz-iv/setup-stripe-payments
Browse files Browse the repository at this point in the history
Setup stripe payments
  • Loading branch information
OlehShumov authored Dec 15, 2023
2 parents b73cf25 + 92af8ff commit 5725648
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 71 deletions.
2 changes: 1 addition & 1 deletion book_service/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.8 on 2023-12-15 12:12
# Generated by Django 4.2.8 on 2023-12-15 14:54

import django.core.validators
from django.db import migrations, models
Expand Down
2 changes: 1 addition & 1 deletion borrowing_service/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.8 on 2023-12-15 12:12
# Generated by Django 4.2.8 on 2023-12-15 14:54

import borrowing_service.models
from django.db import migrations, models
Expand Down
15 changes: 0 additions & 15 deletions borrowing_service/migrations/0002_borrowing_is_active.py

This file was deleted.

26 changes: 26 additions & 0 deletions borrowing_service/migrations/0002_initial.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
# Generated by Django 4.2.8 on 2023-12-15 14:54

from django.conf import settings
from django.db import migrations, models
import django.db.models.deletion


class Migration(migrations.Migration):
initial = True

dependencies = [
("borrowing_service", "0001_initial"),
migrations.swappable_dependency(settings.AUTH_USER_MODEL),
]

operations = [
migrations.AddField(
model_name="borrowing",
name="user",
field=models.ForeignKey(
on_delete=django.db.models.deletion.CASCADE,
related_name="borrowings",
to=settings.AUTH_USER_MODEL,
),
),
]
2 changes: 1 addition & 1 deletion borrowing_service/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@


def set_expected_return_date():
return timezone.now() + BORROW_TERM
return (timezone.now() + BORROW_TERM).date()


class Borrowing(models.Model):
Expand Down
42 changes: 42 additions & 0 deletions borrowing_service/serializers.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,10 @@
from rest_framework.exceptions import ValidationError

from borrowing_service.models import Borrowing
from payment_service.serializers import (
PaymentSerializer,
PaymentListSerializer
)
from payment_service.services import get_payment


Expand Down Expand Up @@ -40,3 +44,41 @@ def create(self, validated_data):
)
get_payment(borrowing)
return borrowing


class BorrowingListSerializer(BorrowingSerializer):
payments = PaymentListSerializer(
many=True, read_only=True
)

class Meta:
model = Borrowing
fields = (
"pk",
"borrow_date",
"expected_return_date",
"actual_return_date",
"book",
"user",
"is_active",
"payments"
)


class BorrowingDetailSerializer(BorrowingSerializer):
payments = PaymentSerializer(
many=True, read_only=True
)

class Meta:
model = Borrowing
fields = (
"pk",
"borrow_date",
"expected_return_date",
"actual_return_date",
"book",
"user",
"is_active",
"payments"
)
9 changes: 8 additions & 1 deletion borrowing_service/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
from borrowing_service.serializers import (
BorrowingSerializer,
BorrowingCreateSerializer,
BorrowingDetailSerializer,
BorrowingListSerializer,
)
from payment_service.services import get_payment

Expand Down Expand Up @@ -42,6 +44,11 @@ def get_serializer_class(self):

if self.action == "create":
return BorrowingCreateSerializer
if self.action == "retrieve":
return BorrowingDetailSerializer
if self.action == "list":
return BorrowingListSerializer

return BorrowingSerializer

def perform_create(self, serializer):
Expand All @@ -57,7 +64,7 @@ def borrowing_return(request, pk):
if request.method == "POST":
if borrowing.is_active:
borrowing.is_active = False
borrowing.actual_return_date = timezone.now()
borrowing.actual_return_date = timezone.now().date()
get_payment(borrowing)
borrowing.book.inventory += 1
borrowing.book.save()
Expand Down
2 changes: 0 additions & 2 deletions core/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,8 +144,6 @@
),
}

DOMAIN = "http://localhost:8000"

SIMPLE_JWT = {
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=60),
"REFRESH_TOKEN_LIFETIME": timedelta(days=1),
Expand Down
2 changes: 1 addition & 1 deletion customer/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.8 on 2023-12-15 12:12
# Generated by Django 4.2.8 on 2023-12-15 14:54

import customer.models
from django.db import migrations, models
Expand Down
2 changes: 1 addition & 1 deletion payment_service/migrations/0001_initial.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# Generated by Django 4.2.8 on 2023-12-15 12:12
# Generated by Django 4.2.8 on 2023-12-15 14:54

from django.db import migrations, models
import django.db.models.deletion
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Generated by Django 4.2.8 on 2023-12-15 16:06

from django.db import migrations, models


class Migration(migrations.Migration):
dependencies = [
("payment_service", "0001_initial"),
]

operations = [
migrations.AlterField(
model_name="payment",
name="money_to_be_paid",
field=models.DecimalField(
blank=True, decimal_places=2, max_digits=10000, null=True
),
),
migrations.AlterField(
model_name="payment",
name="session_id",
field=models.CharField(blank=True, max_length=255, null=True),
),
migrations.AlterField(
model_name="payment",
name="session_url",
field=models.URLField(blank=True, null=True),
),
]
8 changes: 5 additions & 3 deletions payment_service/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ class PaymentTypes(models.TextChoices):
borrowing = models.ForeignKey(
Borrowing, on_delete=models.CASCADE, related_name="payments"
)
session_url = models.URLField()
session_id = models.CharField(max_length=255)
money_to_be_paid = models.DecimalField(max_digits=10000, decimal_places=2)
session_url = models.URLField(null=True, blank=True)
session_id = models.CharField(max_length=255, null=True, blank=True)
money_to_be_paid = models.DecimalField(
max_digits=10000, decimal_places=2, null=True, blank=True
)
11 changes: 6 additions & 5 deletions payment_service/serializers.py
Original file line number Diff line number Diff line change
@@ -1,24 +1,25 @@
from rest_framework import serializers
from rest_framework.serializers import ModelSerializer

from borrowing_service.serializers import BorrowingSerializer
from payment_service.models import Payment


class PaymentSerializer(ModelSerializer):

class PaymentSerializer(serializers.ModelSerializer):
class Meta:
model = Payment
fields = "__all__"


class PaymentListSerializer(PaymentSerializer):
borrowing = BorrowingSerializer()
borrowing = serializers.StringRelatedField(many=False, read_only=True)

class Meta:
model = Payment
fields = (
"id",
"borrowing",
"money_to_be_paid",
"payment_type",
"money_to_be_paid"
"status",
"money_to_be_paid",
)
56 changes: 35 additions & 21 deletions payment_service/services.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
from __future__ import annotations

from datetime import datetime

import stripe
from decimal import Decimal

from django.urls import reverse_lazy, reverse
from stripe.checkout import Session

from borrowing_service.models import Borrowing
Expand All @@ -10,21 +15,22 @@

def calculate_payment_amount(borrowing: Borrowing) -> int:
"""Calculates amount user has to pay for borrowing"""
borrowing_days = (borrowing.expected_return_date.date()

borrowing_days = (borrowing.expected_return_date
- borrowing.borrow_date).days
book_price = borrowing.book.daily_fee
return int(book_price * borrowing_days * 100)


def calculate_fine_amount(borrowing: Borrowing) -> int:
"""Calculates amount user has to pay for overdue expected return date"""
overdue_days = (borrowing.actual_return_date.date()
overdue_days = (borrowing.actual_return_date
- borrowing.expected_return_date).days
book_price = borrowing.book.daily_fee
return int(book_price * 2 * overdue_days * 100)


def get_checkout_session(borrowing: Borrowing) -> Session:
def get_checkout_session(borrowing: Borrowing, payment_id: int) -> Session:
if (
borrowing.actual_return_date
and borrowing.actual_return_date > borrowing.expected_return_date
Expand All @@ -33,41 +39,49 @@ def get_checkout_session(borrowing: Borrowing) -> Session:
else:
payment_amount = calculate_payment_amount(borrowing)

success_url = reverse("payment_service:success", args=[payment_id])
cancel_url = reverse("payment_service:cancel", args=[payment_id])
return Session.create(
payment_method_types=["card"],
line_items=[
{
"price": stripe.Price.create(
currency="usd",
unit_amount=payment_amount,
product_data={
"name": borrowing.book.title
},
product_data={"name": borrowing.book.title},
),
"quantity": 1,
},
],
mode="payment",
success_url=settings.DOMAIN + "/success/",
cancel_url=settings.DOMAIN + "/cancel/",
success_url=success_url,
cancel_url=cancel_url,
)


def get_payment(borrowing: Borrowing) -> Payment:
def get_payment(borrowing: Borrowing) -> Payment | None:
"""Create payment instance for borrowing"""
checkout_session = get_checkout_session(borrowing)
if (
borrowing.actual_return_date
and borrowing.actual_return_date > borrowing.expected_return_date
):
payment_type = Payment.PaymentTypes.FINE
else:
payment_type = Payment.PaymentTypes.PAYMENT
payment_type = Payment.PaymentTypes.PAYMENT

if not borrowing.is_active:
if (
borrowing.actual_return_date
and borrowing.actual_return_date > borrowing.expected_return_date
):
payment_type = Payment.PaymentTypes.FINE
else:
return None

return Payment.objects.create(
payment = Payment.objects.create(
borrowing=borrowing,
payment_type=payment_type,
session_url=checkout_session.url,
session_id=checkout_session.id,
money_to_be_paid=checkout_session.amount_total,
)
checkout_session = get_checkout_session(borrowing, payment.id)

payment.session_id = checkout_session.id
payment.session_url = checkout_session.url
payment.money_to_be_paid = checkout_session.amount_total

payment.save()

return payment
9 changes: 2 additions & 7 deletions payment_service/urls.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,13 @@
from django.urls import path, include
from rest_framework import routers

from payment_service.views import CreateCheckoutSessionView, PaymentViewSet
from payment_service.views import PaymentViewSet

router = routers.DefaultRouter()
router.register("payments", PaymentViewSet, basename="payments")

urlpatterns = [
path(
"create-checkout-session/<int:pk>/",
CreateCheckoutSessionView.as_view(),
name="create-checkout-session",
),
path("", include(router.urls))
path("", include(router.urls)),
]

app_name = "payment_service"
Loading

0 comments on commit 5725648

Please sign in to comment.