Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Payments | New api -- item-purchase-history #325

Merged
merged 5 commits into from
Jun 21, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/payments/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ Django image reads settings from environment variables, default settings for tes

```shell
python -m venv venv ## windows
./venv/scripts/activavte ## windows
./venv/scripts/activate ## windows

virtualenv venv ## linux
source ../venv/bin/activate ## linux
Expand Down
6 changes: 6 additions & 0 deletions backend/payments/apps/base/classes.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,9 @@ def __convert_drf_to_dataclass(self, data_model, serializer: dict):
)
raise DifferentStructureError
return data_model_data


class ListAdminMixin(object):
def __init__(self, model, admin_site):
self.list_display = [field.name for field in model._meta.fields]
super(ListAdminMixin, self).__init__(model, admin_site)
9 changes: 7 additions & 2 deletions backend/payments/apps/base/serializer.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
from apps.base.fields import MoneyAmountSerializerField
from apps.base.schemas import EnumCurrencies, PaymentServices, PaymentTypes
from django.conf import settings
from rest_enumfield import EnumField
from rest_framework import serializers

Expand All @@ -10,5 +10,10 @@ class PaymentServiceSerializer(serializers.Serializer):


class MoneySerializer(serializers.Serializer):
amount = MoneyAmountSerializerField()
# amount = MoneyAmountSerializerField()
amount = serializers.DecimalField(
min_value=0,
max_digits=settings.MAX_BALANCE_DIGITS,
decimal_places=2,
)
currency = EnumField(choices=EnumCurrencies)
11 changes: 11 additions & 0 deletions backend/payments/apps/base/utils/classmethod.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from typing import TypeVar

import rollbar
from apps.base.classes import ListAdminMixin
from django.contrib import admin
from django.db import transaction
from django.db.models import Model
from django.http import HttpResponseServerError
Expand Down Expand Up @@ -52,3 +54,12 @@ def add_change_balance_method(
setattr(obj, django_field, new_balance)
obj.save()
return obj


def register_admin_classes(models):
for model in models:
admin_class = type('AdminClass', (ListAdminMixin, admin.ModelAdmin), {})
try:
admin.site.register(model, admin_class)
except admin.sites.AlreadyRegistered:
pass
5 changes: 5 additions & 0 deletions backend/payments/apps/external_payments/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from apps.base.utils.classmethod import register_admin_classes
from django.apps import apps

models = apps.get_models()
register_admin_classes(models)
5 changes: 5 additions & 0 deletions backend/payments/apps/item_purchases/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from apps.base.utils.classmethod import register_admin_classes
from django.apps import apps

models = apps.get_models()
register_admin_classes(models)
26 changes: 26 additions & 0 deletions backend/payments/apps/item_purchases/serializers.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from apps.base.serializer import MoneySerializer, PaymentServiceSerializer
from apps.item_purchases.models import ItemPurchase, ItemPurchaseHistory
from rest_framework import serializers


Expand Down Expand Up @@ -37,3 +38,28 @@ class ItemHistorySerializer(serializers.Serializer):
item_uuid = serializers.UUIDField()
item_price = MoneySerializer()
created_at = serializers.DateTimeField()


class ItemPurchaseHistorySerializer(serializers.Serializer):
history_id = serializers.IntegerField(source='id')
offer_uuid = serializers.UUIDField(source='item_purchase_id.item_uuid')
price = MoneySerializer(source='item_purchase_id.item_price')
purchase_type = serializers.SerializerMethodField()
status = serializers.SerializerMethodField()
created_at = serializers.DateTimeField(source='created_date')

STATUSES = {item.value: item.name.lower() for item in ItemPurchase.ItemPurchaseStatus}

def get_status(self, obj: ItemPurchaseHistory):
_status = obj.item_purchase_id.status
if (
_status == ItemPurchase.ItemPurchaseStatus.REFUNDED
and obj.event_type == obj.ItemPurchaseType.CREATED
):
return ItemPurchase.ItemPurchaseStatus.PAID.label.lower()
return self.STATUSES[_status]

def get_purchase_type(self, obj: ItemPurchaseHistory):
if obj.item_purchase_id.account_from != obj.item_purchase_id.account_to:
return 'gift'
return 'for_self'
17 changes: 17 additions & 0 deletions backend/payments/apps/item_purchases/services/purchase_items.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
)
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db.models import Q
from django.shortcuts import get_object_or_404

from ..models import Invoice, ItemPurchase, ItemPurchaseHistory
Expand Down Expand Up @@ -166,3 +167,19 @@ def create_item_purchase_instance(
event_type=ItemPurchaseHistory.ItemPurchaseType.CREATED,
)
return item_purchase


class ItemPurchaseHistoryData:
def __init__(self, user_uuid: UUID):
self.user_uuid = user_uuid

def get_item_purchase_qs(self):
q_exclude_complete = Q(event_type=ItemPurchaseHistory.ItemPurchaseType.COMPLETED)
q_exclude_paid = Q(item_purchase_id__status=ItemPurchase.ItemPurchaseStatus.PAID)

qs = (
ItemPurchaseHistory.objects.select_related('item_purchase_id')
.filter(item_purchase_id__account_from__user_uuid=self.user_uuid)
.exclude((q_exclude_complete & q_exclude_paid))
)
return qs
4 changes: 4 additions & 0 deletions backend/payments/apps/item_purchases/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,8 @@
urlpatterns = [
path('purchase/', views.PurchaseItemView.as_view({'post': 'create'})),
path('refund/', views.RefundView.as_view({'post': 'create'})),
path(
'item-purchase-history/<uuid:user_uuid>/',
views.ItemPurchaseHistoryView.as_view({'get': 'list'}),
),
]
16 changes: 14 additions & 2 deletions backend/payments/apps/item_purchases/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,18 @@
from django.core.exceptions import ValidationError
from django.http import Http404
from rest_framework import status, viewsets
from rest_framework.mixins import ListModelMixin
from rest_framework.response import Response

from .exceptions import RefundNotAllowedError
from .models import ItemPurchase
from .schemas import PurchaseItemsData, RefundData
from .serializers import PurchaseItemsSerializer, RefundSerializer
from .services.purchase_items import ItemPurchaseRequest
from .serializers import (
ItemPurchaseHistorySerializer,
PurchaseItemsSerializer,
RefundSerializer,
)
from .services.purchase_items import ItemPurchaseHistoryData, ItemPurchaseRequest
from .services.refund import RefundProcessor


Expand Down Expand Up @@ -63,3 +68,10 @@ def create(self, request, *args, **kwargs):
refund_process.take_refund()

return Response(status=status.HTTP_202_ACCEPTED)


class ItemPurchaseHistoryView(ListModelMixin, viewsets.GenericViewSet):
serializer_class = ItemPurchaseHistorySerializer

def get_queryset(self):
return ItemPurchaseHistoryData(self.kwargs['user_uuid']).get_item_purchase_qs()
5 changes: 5 additions & 0 deletions backend/payments/apps/payment_accounts/admin.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from apps.base.utils.classmethod import register_admin_classes
from django.apps import apps

models = apps.get_models()
register_admin_classes(models)