mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-07-07 06:06:31 +00:00
Merge pull request #5 from i701/feat/topups
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 3m15s
All checks were successful
Build and Push Docker Images / Build and Push Docker Images (push) Successful in 3m15s
feature/topups
This commit is contained in:
@ -26,8 +26,11 @@ class TopupAdmin(admin.ModelAdmin):
|
||||
"paid",
|
||||
"paid_at",
|
||||
"created_at",
|
||||
"is_expired",
|
||||
"expires_at",
|
||||
"updated_at",
|
||||
)
|
||||
|
||||
search_fields = (
|
||||
"user__first_name",
|
||||
"user__last_name",
|
||||
@ -35,6 +38,10 @@ class TopupAdmin(admin.ModelAdmin):
|
||||
"user__mobile",
|
||||
)
|
||||
|
||||
@admin.display(boolean=True, description="Expired")
|
||||
def is_expired(self, obj):
|
||||
return obj.is_expired
|
||||
|
||||
|
||||
admin.site.register(Payment, PaymentAdmin)
|
||||
admin.site.register(BillFormula)
|
||||
|
@ -4,9 +4,6 @@ import random
|
||||
from django.core.management.base import BaseCommand
|
||||
from django.utils import timezone
|
||||
from faker import Faker
|
||||
from billing.models import (
|
||||
Payment,
|
||||
)
|
||||
from billing.models import Topup
|
||||
from api.models import User
|
||||
|
||||
@ -40,12 +37,12 @@ class Command(BaseCommand):
|
||||
for _ in range(number):
|
||||
random_user = random.choice(users)
|
||||
|
||||
paid_status = fake.boolean(chance_of_getting_true=80)
|
||||
paid_at_date = fake.date_time_this_year() if paid_status else None
|
||||
|
||||
if paid_at_date and timezone.is_naive(paid_at_date):
|
||||
paid_at_date = timezone.make_aware(paid_at_date)
|
||||
|
||||
expires_at_date = timezone.now() + timezone.timedelta(
|
||||
minutes=10,
|
||||
)
|
||||
print(
|
||||
f"Creating topup for user {getattr(random_user, 'id', None)} expires at: {expires_at_date}"
|
||||
)
|
||||
Topup.objects.create(
|
||||
amount=fake.pydecimal(
|
||||
left_digits=4,
|
||||
@ -54,10 +51,9 @@ class Command(BaseCommand):
|
||||
min_value=100.00,
|
||||
max_value=5000.00,
|
||||
),
|
||||
paid=paid_status,
|
||||
user=random_user,
|
||||
paid_at=paid_at_date,
|
||||
updated_at=timezone.now(),
|
||||
expires_at=expires_at_date,
|
||||
)
|
||||
|
||||
self.stdout.write(self.style.SUCCESS(f"Successfully seeded {number} topups."))
|
||||
|
@ -0,0 +1,26 @@
|
||||
# Generated by Django 5.2 on 2025-07-04 06:10
|
||||
|
||||
from django.db import migrations, models
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("billing", "0007_topup_paid_at"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.AlterModelOptions(
|
||||
name="topup",
|
||||
options={"ordering": ["-created_at"]},
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="topup",
|
||||
name="expired",
|
||||
field=models.BooleanField(default=False),
|
||||
),
|
||||
migrations.AddField(
|
||||
model_name="topup",
|
||||
name="expires_at",
|
||||
field=models.DateTimeField(blank=True, null=True),
|
||||
),
|
||||
]
|
16
billing/migrations/0009_remove_topup_expired.py
Normal file
16
billing/migrations/0009_remove_topup_expired.py
Normal file
@ -0,0 +1,16 @@
|
||||
# Generated by Django 5.2 on 2025-07-04 11:13
|
||||
|
||||
from django.db import migrations
|
||||
|
||||
|
||||
class Migration(migrations.Migration):
|
||||
dependencies = [
|
||||
("billing", "0008_alter_topup_options_topup_expired_topup_expires_at"),
|
||||
]
|
||||
|
||||
operations = [
|
||||
migrations.RemoveField(
|
||||
model_name="topup",
|
||||
name="expired",
|
||||
),
|
||||
]
|
@ -53,9 +53,16 @@ class Topup(models.Model):
|
||||
paid = models.BooleanField(default=False)
|
||||
paid_at = models.DateTimeField(null=True, blank=True)
|
||||
mib_reference = models.CharField(default="", null=True, blank=True)
|
||||
expires_at = models.DateTimeField(null=True, blank=True)
|
||||
created_at = models.DateTimeField(default=timezone.now)
|
||||
updated_at = models.DateTimeField(auto_now=True)
|
||||
|
||||
@property
|
||||
def is_expired(self):
|
||||
if self.expires_at is None:
|
||||
return False
|
||||
return timezone.now() > self.expires_at
|
||||
|
||||
def __str__(self):
|
||||
return f"Topup for {self.user}"
|
||||
|
||||
|
@ -21,6 +21,7 @@ class UpdatePaymentSerializer(serializers.ModelSerializer):
|
||||
|
||||
class TopupSerializer(serializers.ModelSerializer):
|
||||
user = serializers.SerializerMethodField()
|
||||
is_expired = serializers.SerializerMethodField()
|
||||
|
||||
def get_user(self, obj):
|
||||
user = obj.user
|
||||
@ -33,6 +34,9 @@ class TopupSerializer(serializers.ModelSerializer):
|
||||
}
|
||||
return None
|
||||
|
||||
def get_is_expired(self, obj):
|
||||
return obj.is_expired
|
||||
|
||||
class Meta: # type: ignore
|
||||
model = Topup
|
||||
fields = [
|
||||
@ -41,6 +45,7 @@ class TopupSerializer(serializers.ModelSerializer):
|
||||
"user",
|
||||
"paid",
|
||||
"mib_reference",
|
||||
"is_expired",
|
||||
"created_at",
|
||||
"updated_at",
|
||||
]
|
||||
|
@ -367,3 +367,33 @@ class VerifyTopupPaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIVi
|
||||
{"message": "Topup payment verification failed."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
|
||||
|
||||
class DeleteTopupView(StaffEditorPermissionMixin, generics.DestroyAPIView):
|
||||
queryset = Topup.objects.all()
|
||||
serializer_class = TopupSerializer
|
||||
lookup_field = "pk"
|
||||
|
||||
def delete(self, request, *args, **kwargs):
|
||||
instance = self.get_object()
|
||||
user = request.user
|
||||
if instance.is_expired:
|
||||
return Response(
|
||||
{"message": "Expired topups cannot be deleted."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
if (
|
||||
instance.user != user
|
||||
and getattr(user, "is_admin")
|
||||
and not user.is_superuser
|
||||
):
|
||||
return Response(
|
||||
{"message": "You are not authorized to delete this topup."},
|
||||
status=status.HTTP_403_FORBIDDEN,
|
||||
)
|
||||
if instance.paid:
|
||||
return Response(
|
||||
{"message": "Paid topups cannot be deleted."},
|
||||
status=status.HTTP_400_BAD_REQUEST,
|
||||
)
|
||||
return super().delete(request, *args, **kwargs)
|
||||
|
Reference in New Issue
Block a user