mirror of
https://github.com/i701/sarlink-portal-api.git
synced 2025-07-07 18:26:30 +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",
|
||||||
"paid_at",
|
"paid_at",
|
||||||
"created_at",
|
"created_at",
|
||||||
|
"is_expired",
|
||||||
|
"expires_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
)
|
)
|
||||||
|
|
||||||
search_fields = (
|
search_fields = (
|
||||||
"user__first_name",
|
"user__first_name",
|
||||||
"user__last_name",
|
"user__last_name",
|
||||||
@ -35,6 +38,10 @@ class TopupAdmin(admin.ModelAdmin):
|
|||||||
"user__mobile",
|
"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(Payment, PaymentAdmin)
|
||||||
admin.site.register(BillFormula)
|
admin.site.register(BillFormula)
|
||||||
|
@ -4,9 +4,6 @@ import random
|
|||||||
from django.core.management.base import BaseCommand
|
from django.core.management.base import BaseCommand
|
||||||
from django.utils import timezone
|
from django.utils import timezone
|
||||||
from faker import Faker
|
from faker import Faker
|
||||||
from billing.models import (
|
|
||||||
Payment,
|
|
||||||
)
|
|
||||||
from billing.models import Topup
|
from billing.models import Topup
|
||||||
from api.models import User
|
from api.models import User
|
||||||
|
|
||||||
@ -40,12 +37,12 @@ class Command(BaseCommand):
|
|||||||
for _ in range(number):
|
for _ in range(number):
|
||||||
random_user = random.choice(users)
|
random_user = random.choice(users)
|
||||||
|
|
||||||
paid_status = fake.boolean(chance_of_getting_true=80)
|
expires_at_date = timezone.now() + timezone.timedelta(
|
||||||
paid_at_date = fake.date_time_this_year() if paid_status else None
|
minutes=10,
|
||||||
|
)
|
||||||
if paid_at_date and timezone.is_naive(paid_at_date):
|
print(
|
||||||
paid_at_date = timezone.make_aware(paid_at_date)
|
f"Creating topup for user {getattr(random_user, 'id', None)} expires at: {expires_at_date}"
|
||||||
|
)
|
||||||
Topup.objects.create(
|
Topup.objects.create(
|
||||||
amount=fake.pydecimal(
|
amount=fake.pydecimal(
|
||||||
left_digits=4,
|
left_digits=4,
|
||||||
@ -54,10 +51,9 @@ class Command(BaseCommand):
|
|||||||
min_value=100.00,
|
min_value=100.00,
|
||||||
max_value=5000.00,
|
max_value=5000.00,
|
||||||
),
|
),
|
||||||
paid=paid_status,
|
|
||||||
user=random_user,
|
user=random_user,
|
||||||
paid_at=paid_at_date,
|
|
||||||
updated_at=timezone.now(),
|
updated_at=timezone.now(),
|
||||||
|
expires_at=expires_at_date,
|
||||||
)
|
)
|
||||||
|
|
||||||
self.stdout.write(self.style.SUCCESS(f"Successfully seeded {number} topups."))
|
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 = models.BooleanField(default=False)
|
||||||
paid_at = models.DateTimeField(null=True, blank=True)
|
paid_at = models.DateTimeField(null=True, blank=True)
|
||||||
mib_reference = models.CharField(default="", 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)
|
created_at = models.DateTimeField(default=timezone.now)
|
||||||
updated_at = models.DateTimeField(auto_now=True)
|
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):
|
def __str__(self):
|
||||||
return f"Topup for {self.user}"
|
return f"Topup for {self.user}"
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ class UpdatePaymentSerializer(serializers.ModelSerializer):
|
|||||||
|
|
||||||
class TopupSerializer(serializers.ModelSerializer):
|
class TopupSerializer(serializers.ModelSerializer):
|
||||||
user = serializers.SerializerMethodField()
|
user = serializers.SerializerMethodField()
|
||||||
|
is_expired = serializers.SerializerMethodField()
|
||||||
|
|
||||||
def get_user(self, obj):
|
def get_user(self, obj):
|
||||||
user = obj.user
|
user = obj.user
|
||||||
@ -33,6 +34,9 @@ class TopupSerializer(serializers.ModelSerializer):
|
|||||||
}
|
}
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
def get_is_expired(self, obj):
|
||||||
|
return obj.is_expired
|
||||||
|
|
||||||
class Meta: # type: ignore
|
class Meta: # type: ignore
|
||||||
model = Topup
|
model = Topup
|
||||||
fields = [
|
fields = [
|
||||||
@ -41,6 +45,7 @@ class TopupSerializer(serializers.ModelSerializer):
|
|||||||
"user",
|
"user",
|
||||||
"paid",
|
"paid",
|
||||||
"mib_reference",
|
"mib_reference",
|
||||||
|
"is_expired",
|
||||||
"created_at",
|
"created_at",
|
||||||
"updated_at",
|
"updated_at",
|
||||||
]
|
]
|
||||||
|
@ -367,3 +367,33 @@ class VerifyTopupPaymentAPIView(StaffEditorPermissionMixin, generics.UpdateAPIVi
|
|||||||
{"message": "Topup payment verification failed."},
|
{"message": "Topup payment verification failed."},
|
||||||
status=status.HTTP_400_BAD_REQUEST,
|
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