feat(billing): WIP Add Topup model, filters, serializers, and views for topup management

This commit is contained in:
2025-07-03 17:13:25 +05:00
parent bae0882879
commit c07d3c93d2
7 changed files with 172 additions and 7 deletions

View File

@ -15,9 +15,9 @@ from api.tasks import add_new_devices_to_omada
from apibase.env import BASE_DIR, env
import logging
from .models import Device, Payment
from .serializers import PaymentSerializer, UpdatePaymentSerializer
from .filters import PaymentFilter
from .models import Device, Payment, Topup
from .serializers import PaymentSerializer, UpdatePaymentSerializer, TopupSerializer
from .filters import PaymentFilter, TopupFilter
env.read_env(os.path.join(BASE_DIR, ".env"))
@ -259,3 +259,91 @@ class DeletePaymentView(StaffEditorPermissionMixin, generics.DestroyAPIView):
devices = instance.devices.all()
devices.update(is_active=False, expiry_date=None, has_a_pending_payment=False)
return super().delete(request, *args, **kwargs)
class ListCreateTopupView(StaffEditorPermissionMixin, generics.ListCreateAPIView):
queryset = Topup.objects.all()
serializer_class = TopupSerializer
filter_backends = [DjangoFilterBackend]
filterset_fields = "__all__"
filterset_class = TopupFilter
def create(self, request, *args, **kwargs):
data = request.data
user = request.user
amount = data.get("amount")
if not amount:
return Response(
{"message": "amount is required."},
status=status.HTTP_400_BAD_REQUEST,
)
topup = Topup.objects.create(amount=amount, user=user)
serializer = TopupSerializer(topup)
return Response(serializer.data, status=status.HTTP_201_CREATED)
class VerifyTopupPaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIView):
queryset = Topup.objects.all()
serializer_class = TopupSerializer
lookup_field = "pk"
def verify_transfer_topup(self, data, topup):
if not PAYMENT_BASE_URL:
raise ValueError(
"PAYMENT_BASE_URL is not set. Please set it in your environment variables."
)
logger.info(data)
response = requests.post(
f"{PAYMENT_BASE_URL}/verify-payment",
json=data,
headers={"Content-Type": "application/json"},
)
try:
response.raise_for_status()
except requests.exceptions.HTTPError as e:
logger.error(f"HTTPError: {e}")
return False # Or handle the error as appropriate
mib_resp = response.json()
print(mib_resp)
if not response.json().get("success"):
return mib_resp["success"]
else:
topup.paid = True
# topup.paid_at = timezone.now() # Assuming Topup model has paid_at field
topup.mib_reference = mib_resp["transaction"]["ref"] or ""
topup.save()
return True
def update(self, request, *args, **kwargs):
topup_instance = self.get_object()
user = request.user
if topup_instance.paid:
return Response(
{"message": "Payment has already been verified."},
status=status.HTTP_400_BAD_REQUEST,
)
if topup_instance.user != user and not user.is_superuser:
return Response(
{"message": "You are not allowed to pay for this topup."},
status=status.HTTP_403_FORBIDDEN,
)
data = {
"benefName": f"{user.first_name} {user.last_name}", # type: ignore
"accountNo": user.acc_no, # type: ignore
"absAmount": topup_instance.amount,
"time": localtime(timezone.now() + timedelta(minutes=5)).strftime(
"%Y-%m-%d %H:%M"
),
}
topup_status = self.verify_transfer_topup(data, topup_instance)
if topup_status:
return Response(
{"message": "Topup payment verified successfully."},
status=status.HTTP_200_OK,
)
else:
return Response(
{"message": "Topup payment verification failed."},
status=status.HTTP_400_BAD_REQUEST,
)