i701 f6f77bb0e5
Add wallet balance to User model and implement Atoll/Island management
- Added `wallet_balance` field to the User model.
- Updated UserAdmin to include `wallet_balance` in the admin interface.
- Created serializers and views for Atoll and Island management.
- Implemented endpoints for listing, creating, and updating Atolls and Islands.
- Enhanced payment processing with UUIDs for Payment and Topup models.
- Added migration files for new fields and constraints.
- Improved error handling and validation in various views.
- Updated email templates for better responsiveness and SEO.
2025-01-20 20:59:16 +05:00

142 lines
4.8 KiB
Python

# Create your views here.
# billing/views.py
from .models import Payment, Device
from datetime import datetime, timedelta
import requests
from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from decouple import config
from .serializers import PaymentSerializer
from rest_framework.permissions import AllowAny
from api.mixins import StaffEditorPermissionMixin
from rest_framework import generics
class InsufficientFundsError(Exception):
pass
class CreatePaymentView(StaffEditorPermissionMixin, generics.CreateAPIView):
serializer_class = PaymentSerializer
queryset = Payment.objects.all()
def create(self, request):
data = request.data
user = request.user
amount = data.get("amount")
number_of_months = data.get("number_of_months")
device_ids = data.get("device_ids", [])
print(amount, number_of_months, device_ids)
if not amount or not number_of_months:
return Response(
{"message": "amount and number_of_months are required."},
status=status.HTTP_400_BAD_REQUEST,
)
if not device_ids:
return Response(
{"message": "device_ids are required."},
status=status.HTTP_400_BAD_REQUEST,
)
# Create payment
payment = Payment.objects.create(
amount=amount,
number_of_months=number_of_months,
paid=data.get("paid", False),
user=user,
)
# Connect devices to payment
devices = Device.objects.filter(id__in=device_ids, user=user)
payment.devices.set(devices)
serializer = PaymentSerializer(payment)
return Response(serializer.data, status=status.HTTP_201_CREATED)
class VerifyPaymentView(StaffEditorPermissionMixin, generics.UpdateAPIView):
serializer_class = PaymentSerializer
queryset = Payment.objects.all()
def update(self, request, *args, **kwargs):
data = request.data
user = request.user
print(user)
method = data.get("method")
payment_id = data.get("payment_id")
abs_amount = data.get("abs_amount")
if not method:
return Response(
{"message": "method is required. 'WALLET' or 'TRANSFER'"},
status=status.HTTP_400_BAD_REQUEST,
)
if not payment_id:
return Response(
{"message": "payment_id is required."},
status=status.HTTP_400_BAD_REQUEST,
)
if not abs_amount:
return Response(
{"message": "abs_amount is required."},
status=status.HTTP_400_BAD_REQUEST,
)
try:
payment = Payment.objects.get(id=payment_id)
devices = payment.devices.all()
if data["type"] == "WALLET":
print("processing WALLET payment")
self.process_wallet_payment(user, payment, float(data["abs_amount"]))
elif data["type"] == "TRANSFER":
self.verify_external_payment(data, payment)
# Update devices
expiry_date = datetime.now() + timedelta(days=30 * payment.number_of_months)
devices.update(is_active=True, expiry_date=expiry_date)
return Response({"message": "Payment verified successfully."})
except Payment.DoesNotExist:
return Response(
{"message": "Payment not found."}, status=status.HTTP_404_NOT_FOUND
)
except InsufficientFundsError:
return Response(
{"message": "Insufficient funds in wallet."},
status=status.HTTP_400_BAD_REQUEST,
)
except Exception as e:
return Response(
{"message": str(e)}, status=status.HTTP_500_INTERNAL_SERVER_ERROR
)
def process_wallet_payment(self, user, payment, amount):
print("processing wallet payment")
print(user, amount)
if user.wallet_balance < amount:
return Response(
{"message": "Insufficient funds in wallet."},
status=status.HTTP_400_BAD_REQUEST,
)
payment.paid = True
payment.paid_at = datetime.now()
payment.method = "WALLET"
payment.save()
user.wallet_balance -= amount
user.save()
def verify_external_payment(self, data, payment):
response = requests.post(
f"{config('PAYMENT_VERIFY_BASE_URL')}/verify-payment",
json=data,
headers={"Content-Type": "application/json"},
)
response.raise_for_status()
print(response.json())
if not response.json().get("success"):
raise Exception("Payment verification failed.")