added new functionalities of G-Token

This commit is contained in:
rizwanisready
2024-04-24 13:45:16 +05:30
parent 9e38f7ca13
commit 0cb02f0110
26 changed files with 414 additions and 57 deletions

View File

@@ -207,26 +207,57 @@ class PaymentProcessingService:
self.charge_data = webhook_data["data"]["object"]
self.customer_id = self._get_customer_id()
self.transaction = self._get_transaction_by_id()
self.principal_id = self.transaction.principal.id
self.principal = self.transaction.principal
def _get_customer_id(self):
# Access the customer ID from the charge object
return self.charge_data.get("customer", None)
def _get_transaction_by_id(self):
print("self.metadata: ", self.charge_data["metadata"])
logger.debug("self.metadata: ", self.charge_data["metadata"])
logger.debug("transaction_id: ", self.charge_data["metadata"]["transaction_id"])
transaction_id = self.charge_data["metadata"]["transaction_id"]
print("_get_transaction_by_id: ", transaction_id)
return Transaction.objects.get(id=int(transaction_id))
if transaction_id:
try:
logger.debug("_get_transaction_by_id: ", transaction_id)
return Transaction.objects.get(id=int(transaction_id))
except Transaction.DoesNotExist:
logger.error(f"Transaction ID {transaction_id} not found.")
return None
def _get_subscription(self):
logger.debug("subscription_id: ", self.charge_data["metadata"]["subscription_id"])
subscription_id = self.charge_data["metadata"]["subscription_id"]
if subscription_id:
try:
return Subscription.objects.get(id=int(subscription_id))
except Subscription.DoesNotExist:
logger.error(f"Subscription ID {subscription_id} not found.")
return None
def _get_principal_subscription_by_id(self):
# Extract transaction_id from webhook metadata
principal_subscription = self.charge_data["metadata"][
"principal_subscription_id"
]
print("principal_subscription: ", principal_subscription)
# Fetch the Transaction instance using the transaction_id
return PrincipalSubscription.objects.get(id=int(principal_subscription))
order_id = self.charge_data["metadata"]["order_id"]
try:
subscription = self._get_subscription()
subscription_days = subscription.plan.days
today = timezone.now().date()
last_date = today + timedelta(days=int(subscription_days))
principal_subscription = PrincipalSubscription.objects.create(
principal=self.principal,
subscription=subscription,
is_paid=True,
order_id=order_id,
start_date=today,
end_date=last_date,
grace_period_end_date=last_date + timedelta(days=15),
)
return principal_subscription
except Subscription.DoesNotExist:
logger.error("SOmething Went Wrong inside _get_principal_subscription_by_id().")
return None
def process_event(self):
if self.event_type == "checkout.session.completed":
@@ -245,7 +276,7 @@ class PaymentProcessingService:
referral_record = ReferralRecord.objects.filter(
active=True,
deleted=False,
referred_principal_id=self.principal_id,
referred_principal_id=self.principal.id,
is_completed=True,
).first()
@@ -263,9 +294,25 @@ class PaymentProcessingService:
.order_by("-end_date")
.first()
)
if active_subscription:
self._credit_good_time_coin(referral_record.referrer_principal)
subscription = self._get_principal_subscription_by_id()
if subscription:
# Calculate the reward value
percentage = (
subscription.referral_percentage * subscription.amount / 100
)
# Create a reward entry
ReferralRecordReward.objects.create(
referral_record=referral_record,
subscription=subscription,
coins=1, # Assuming this is a default or a calculated value
value=percentage,
)
self._credit_good_time_coin(
referral_record.referrer_principal, percentage
)
# Here's where you call _update_reward
self._update_reward(
referral_record=referral_record,
@@ -282,16 +329,16 @@ class PaymentProcessingService:
has_active_subscription=False,
)
def _credit_good_time_coin(self, referrer_principal):
wallet, created = Wallet.objects.get_or_create(principal=referrer_principal)
wallet.coins += 1
wallet.save()
def _credit_good_time_coin(self, referrer_principal, percentage):
# wallet, created = Wallet.objects.get_or_create(principal=referrer_principal)
# wallet.coins += 1
# wallet.save()
Transaction.objects.create(
principal=referrer_principal,
transaction_type=TransactionType.CREDIT,
payment_method="",
transaction_status=TransactionStatus.SUCCESS,
amount=0,
amount=percentage,
coins=1,
comment="Referral reward",
# Populate other fields as necessary, such as `order_id`, `product_id`, or `reference_id` if applicable

View File

@@ -74,8 +74,9 @@ class ReferralRecordRewardAdmin(admin.ModelAdmin):
"get_subscription_name",
"coins",
"value",
"unique_token",
)
search_fields = ("referral_record__id", "subscription__name", "coins")
search_fields = ("referral_record__id", "subscription__title", "coins")
list_filter = ("subscription",)
raw_id_fields = ("referral_record", "subscription")
@@ -85,7 +86,7 @@ class ReferralRecordRewardAdmin(admin.ModelAdmin):
get_referral_record_id.short_description = "Referral Record ID"
def get_subscription_name(self, obj):
return obj.subscription.name
return obj.subscription.title
get_subscription_name.short_description = "Subscription Name"

View File

@@ -11,6 +11,7 @@ from accounts.models import (
from manage_referrals.models import (
ReferralCode,
ReferralRecord,
ReferralRecordReward,
)
from goodtimes import constants, date_utils
@@ -37,3 +38,16 @@ class ReferralRecordSerializer(serializers.ModelSerializer):
def get_join_at(self, obj):
return date_utils.format_date_to_string(obj.created_on)
class ReferralRecordRewardSerializer(serializers.ModelSerializer):
class Meta:
model = ReferralRecordReward
fields = [
"referral_record",
"subscription",
"redeem",
"coins",
"unique_token",
"value",
]

View File

@@ -14,4 +14,14 @@ urlpatterns = [
views.ReferralRecordViews.as_view(),
name="referral_record",
),
path(
"referral-record-rewards/",
views.RewardListView.as_view(),
name="referral_record_reward",
),
path(
"redeem-reward/<uuid:unique_token>/",
views.RedeemRewardView.as_view(),
name="redeem_reward",
),
]

View File

@@ -1,12 +1,15 @@
from rest_framework import status
from rest_framework.views import APIView
from django.conf import settings
from manage_referrals.models import ReferralCode, ReferralRecord
from manage_referrals.models import ReferralCode, ReferralRecord, ReferralRecordReward
from django.shortcuts import get_object_or_404
from goodtimes import constants
from django.db import transaction
from goodtimes.utils import ApiResponse
from manage_wallets.models import WithdrawalRequest
from .serializers import (
ReferralCodeSerializer,
ReferralRecordRewardSerializer,
ReferralRecordSerializer,
)
from rest_framework.permissions import IsAuthenticated
@@ -49,3 +52,75 @@ class ReferralRecordViews(APIView):
"data": {"count": referral_obj.count(), "record": serializer_obj.data},
}
return ApiResponse.success(**success_message)
class RewardListView(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
model = ReferralRecordReward
serializer = ReferralRecordRewardSerializer
def get(self, request):
# Filter rewards based on specified conditions
rewards_query = ReferralRecordReward.objects.filter(
referral_record__active=True,
referral_record__deleted=False,
redeem=False,
deleted=False,
active=True,
)
# Serialize the results
rewards_serializer = ReferralRecordRewardSerializer(rewards_query, many=True)
# Get the count of unredeemed rewards
unredeemed_count = rewards_query.count()
success_message = {
"status": status.HTTP_200_OK,
"message": constants.SUCCESS,
"data": {
"reward_count": unredeemed_count,
"rewards": rewards_serializer.data,
},
}
return ApiResponse.success(**success_message)
class RedeemRewardView(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
def patch(self, request, unique_token):
# Retrieve the reward using the unique token
try:
reward = ReferralRecordReward.objects.get(
unique_token=unique_token, sell=False
)
except ReferralRecordReward.DoesNotExist:
return ApiResponse.error(
status=status.HTTP_404_NOT_FOUND,
message=constants.FAILURE,
errors="No unsold token found.",
)
# Check if a withdrawal request already exists for this token
if WithdrawalRequest.objects.filter(token=unique_token).exists():
return ApiResponse.error(
status=status.HTTP_400_BAD_REQUEST,
message=constants.FAILURE,
errors="A withdrawal request for this token already exists.",
)
with transaction.atomic():
# Create a new withdrawal request
WithdrawalRequest.objects.create(
principal=request.user, token=unique_token, coins=1, amount=reward.value
)
# Update reward to mark it as sold
reward.sell = True
reward.save()
return ApiResponse.success(
status=status.HTTP_200_OK,
message=constants.SUCCESS,
data="Token sold successfully.",
)

View File

@@ -34,7 +34,7 @@ class ReferralRecordForm(forms.ModelForm):
class ReferralRecordRewardForm(forms.ModelForm):
class Meta:
model = ReferralRecordReward
fields = ["referral_record", "subscription", "coins", "value"]
fields = ["referral_record", "subscription", "coins", "value", "sell"]
class GoodTimeCoinsForm(forms.ModelForm):

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-04-22 14:06
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_referrals", "0008_referralrecordreward_unique_token"),
]
operations = [
migrations.AddField(
model_name="referralrecordreward",
name="redeem",
field=models.BooleanField(default=False),
),
]

View File

@@ -0,0 +1,19 @@
# Generated by Django 5.0.2 on 2024-04-23 07:50
import uuid
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_referrals", "0009_referralrecordreward_redeem"),
]
operations = [
migrations.AlterField(
model_name="referralrecordreward",
name="unique_token",
field=models.UUIDField(default=uuid.uuid4, editable=False),
),
]

View File

@@ -0,0 +1,23 @@
# Generated by Django 5.0.2 on 2024-04-23 14:59
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_referrals", "0010_alter_referralrecordreward_unique_token"),
]
operations = [
migrations.RenameField(
model_name="referralrecordreward",
old_name="redeem",
new_name="sell",
),
migrations.AddField(
model_name="referralrecordreward",
name="withdraw",
field=models.BooleanField(default=False),
),
]

View File

@@ -114,7 +114,7 @@ class ReferralRecord(BaseModel):
db_table = "referral_record"
def __str__(self):
return f"Referral ID: {self.id}, Referrar name: {self.referrer_principal.first_name}, Type: {self.principal_type.name}"
return f"Reward ID: {self.id}, Referrar: {self.referrer_principal.first_name}, Referred to: {self.referred_principal.first_name}"
@classmethod
def filter_invite_records(cls, referrer_principal):
@@ -136,9 +136,11 @@ class ReferralRecordReward(BaseModel):
subscription = models.ForeignKey(
Subscription, on_delete=models.CASCADE, related_name="subscription_reward"
)
sell = models.BooleanField(default=False)
withdraw = models.BooleanField(default=False)
coins = models.PositiveBigIntegerField(default=1)
unique_token = models.UUIDField(
default=uuid.uuid4, editable=False, null=True, blank=True
default=uuid.uuid4, editable=False
)
value = models.DecimalField(max_digits=14, decimal_places=2)

View File

@@ -181,7 +181,7 @@ class ReferralRecordRewardCreateOrUpdateView(LoginRequiredMixin, generic.View):
context.update(kwargs) # Include any additional context data passed to the view
return context
def get(self, request, args, *kwargs):
def get(self, request, *args, **kwargs):
self.object = self.get_object()
# If an object is found, change action to ACTION_UPDATE
@@ -192,7 +192,7 @@ class ReferralRecordRewardCreateOrUpdateView(LoginRequiredMixin, generic.View):
context = self.get_context_data(form=form)
return render(request, self.template_name, context=context)
def post(self, request, args, *kwargs):
def post(self, request, *args, **kwargs):
self.object = self.get_object()
# If an object is found, change action to ACTION_UPDATE

View File

@@ -27,6 +27,7 @@ class SubscriptionForm(forms.ModelForm):
# "long_description",
# "image",
"principal_types",
"referral_percentage",
] # Include all fields you want from the model

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-04-22 13:08
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_subscriptions", "0005_webhookevent_event_type"),
]
operations = [
migrations.AddField(
model_name="subscription",
name="referral_percentage",
field=models.DecimalField(decimal_places=2, default=0.0, max_digits=5),
),
]

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-04-22 13:13
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_subscriptions", "0006_subscription_referral_percentage"),
]
operations = [
migrations.AlterField(
model_name="subscription",
name="referral_percentage",
field=models.DecimalField(decimal_places=2, max_digits=5),
),
]

View File

@@ -29,6 +29,7 @@ class Subscription(BaseModel):
principal_types = models.ManyToManyField(
IAmPrincipalType, related_name="principal_type_subscriptions", blank=True
)
referral_percentage = models.DecimalField(max_digits=5, decimal_places=2)
class Meta:
db_table = "subscription"

View File

@@ -437,20 +437,20 @@ def create_checkout_session(request):
comment="Principal Subscription Initiated",
)
subscription_days = subscription.plan.days
today = timezone.now().date()
last_date = today + timedelta(days=int(subscription_days))
# subscription_days = subscription.plan.days
# today = timezone.now().date()
# last_date = today + timedelta(days=int(subscription_days))
# To Avoid Duplicacy of Principal Subscription
principal_subscription = PrincipalSubscription.objects.create(
principal=request.user,
subscription=subscription,
is_paid=False,
order_id=order_id,
start_date=today,
end_date=last_date,
grace_period_end_date=last_date + timedelta(days=15),
)
# principal_subscription = PrincipalSubscription.objects.create(
# principal=request.user,
# subscription=subscription,
# is_paid=False,
# order_id=order_id,
# start_date=today,
# end_date=last_date,
# grace_period_end_date=last_date + timedelta(days=15),
# )
try:
# customer = stripe.Customer.create(
@@ -491,9 +491,9 @@ def create_checkout_session(request):
metadata={
"principal": str(request.user.id),
"order_id": str(order_id),
# "subscription_id": str(subscription.id),
"subscription_id": str(subscription.id),
"transaction_id": str(transaction.id),
"principal_subscription_id": str(principal_subscription.id),
# "principal_subscription_id": str(principal_subscription.id),
},
)
return JsonResponse({"sessionId": checkout_session["id"]})

View File

@@ -71,3 +71,48 @@ class StripeConnectAccountAdmin(admin.ModelAdmin):
"details_submitted",
)
search_fields = ("principal__name", "stripe_connect_id")
class WithdrawalRequestAdmin(admin.ModelAdmin):
list_display = ("id", "principal", "coins", "token", "amount", "status", "ref_id")
list_filter = ("status", "principal")
search_fields = (
"ref_id",
"token",
"principal__user__username",
) # Adjust if 'principal' has a different relation to User
readonly_fields = ("ref_image", "reply", "notes")
fieldsets = (
(None, {"fields": ("principal", "coins", "token", "amount", "status")}),
(
"Reference Information",
{
"fields": ("ref_image", "ref_id", "notes", "reply"),
"classes": ("collapse",),
},
),
)
# def has_delete_permission(self, request, obj=None):
# # Disable delete if the status is not 'denied' or 'dispute'
# if obj is not None:
# if obj.status in ["denied", "dispute"]:
# return True
# return False
# return True
def has_add_permission(self, request, obj=None):
# You can also control if adding is allowed
return True
def has_change_permission(self, request, obj=None):
# Control the ability to change existing records
if obj is not None:
if obj.status in ["submitted", "review"]:
return True
return False
return True
admin.site.register(models.WithdrawalRequest, WithdrawalRequestAdmin)

View File

@@ -33,4 +33,10 @@ urlpatterns = [
views.WithdrawalRequestView.as_view(),
name="withdrawal-request-view",
),
# checking bank accounts
path(
"check-bank-accounts/",
views.PrincipalBankAccountCheck.as_view(),
name="check_bank_accounts",
),
]

View File

@@ -419,3 +419,26 @@ class WithdrawalRequestView(APIView):
status=status.HTTP_200_OK,
message=constants.SUCCESS,
)
class PrincipalBankAccountCheck(APIView):
authentication_classes = [JWTAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request):
queryset = models.PrincipalBankAccount.objects.filter(principal=request.user)
if queryset:
response = {
"status": status.HTTP_200_OK,
"message": constants.SUCCESS,
"data": True,
}
return ApiResponse.success(**response)
false_response = {
"status": status.HTTP_200_OK,
"message": constants.SUCCESS,
"data": False,
}
return ApiResponse.success(**false_response)

View File

@@ -0,0 +1,18 @@
# Generated by Django 5.0.2 on 2024-04-23 11:49
from django.db import migrations, models
class Migration(migrations.Migration):
dependencies = [
("manage_wallets", "0009_rename_coin_transaction_coins_and_more"),
]
operations = [
migrations.AddField(
model_name="withdrawalrequest",
name="token",
field=models.CharField(blank=True, max_length=255, null=True),
),
]

View File

@@ -3,6 +3,7 @@ from django.db import models
from accounts.models import BaseModel, IAmPrincipal, IAmPrincipalType
from django.db.models.signals import post_save
from django.dispatch import receiver
from manage_referrals.models import ReferralRecordReward
from manage_subscriptions.models import PrincipalSubscription
# Create your models here.
@@ -135,6 +136,7 @@ class WithdrawalRequest(BaseModel):
IAmPrincipal, on_delete=models.CASCADE, related_name="withdrawal_requests"
)
coins = models.IntegerField(default=0)
token = models.CharField(max_length=255, blank=True, null=True)
amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.00)
ref_image = models.ImageField(upload_to="withdrawal", null=True, blank=True)
ref_id = models.CharField(unique=True, max_length=255, null=True, blank=True)

View File

@@ -78,10 +78,20 @@ class StatusUpdateView(LoginRequiredMixin, generic.View):
id = request.POST.get("id")
message = request.POST.get("message")
status = request.POST.get("status")
print("Request.POST: ", request.POST)
if id or message:
try:
instance = self.model.objects.get(id=id)
print("status: ", status)
if status == "transferred":
print("Hello")
bank_account = PrincipalBankAccount.objects.filter(principal=instance.principal)
print("bank_account: ", bank_account)
for account in bank_account:
account.delete()
print("Deleted all accounts")
instance.reply = message
instance.status = status
instance.save()

View File

@@ -21,10 +21,10 @@
Back
</button>
-->
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:coin_list' %}">Coins</a>
<!-- <a class="btn btn-primary mb-2" href="{% url 'manage_referrals:coin_list' %}">Coins</a> -->
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:track_list' %}">Tracking</a>
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:record_list' %}">Referral Record</a>
<!-- <a class="btn btn-primary mb-2" href="{% url 'manage_referrals:reward_list' %}">Rewards</a> -->
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:reward_list' %}">Rewards</a>
</div>
</div>

View File

@@ -16,7 +16,7 @@
<div class="col-lg-12">
<div class="row mb-2">
<div class="col">
<h3>Add Event</h3>
<h3>Rewards</h3>
</div>
<div class="col text-end">
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">

View File

@@ -44,11 +44,13 @@
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
aria-sort="ascending" style="width: 69.2656px;"> Subscription </th>
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
aria-sort="ascending" style="width: 69.2656px;"> Coins </th>
aria-sort="ascending" style="width: 69.2656px;"> Token </th>
<!-- <th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
aria-sort="ascending" style="width: 69.2656px;"> Coins </th> -->
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
aria-sort="ascending" style="width: 69.2656px;"> Value </th>
<th class="sorting" tabindex="7" aria-controls="style-3"
style="width: 79.7969px;">Active</th>
style="width: 79.7969px;">Sell</th>
<th class="dt-no-sorting sorting" tabindex="8" aria-controls="style-3"
style="width: 100.625px;">Action</th>
</tr>
@@ -59,11 +61,12 @@
<td class="checkbox-column text-center sorting_1">{{data_obj.id}}</td>
<td>{{data_obj.referral_record}}</td>
<td>{{data_obj.subscription}}</td>
<td>{{data_obj.coins}}</td>
<td>{{data_obj.unique_token}}</td>
<!-- <td>{{data_obj.coins}}</td> -->
<td>{{data_obj.value}}</td>
<td class="text-center">
<span
class="shadow-none badge {% if data_obj.active %}badge-primary{% else %}badge-danger{% endif %}">{{data_obj.active}}</span>
class="shadow-none badge {% if data_obj.sell %}badge-primary{% else %}badge-danger{% endif %}">{{data_obj.sell}}</span>
</td>
<td class="text-center">
<ul class="table-controls">

View File

@@ -40,16 +40,18 @@
colspan="1" style="width: 69.2656px;"> Record Id </th>
<th tabindex="1" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 44.2344px;">Principal</th>
<th tabindex="2" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 79.7969px;">Coins</th>
<!-- <th tabindex="2" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 79.7969px;">Qty</th> -->
<th tabindex="3" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 77.3281px;">Amount</th>
<th tabindex="3" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 77.3281px;">G-Token</th>
<th tabindex="3" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 77.3281px;">Status</th>
<th tabindex="4" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 143.516px;">Submitted</th>
<th tabindex="5" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 98.875px;">Reply / Update</th>
style="width: 143.516px;">Sold At</th>
<!-- <th tabindex="5" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 98.875px;">Reply / Update</th> -->
<th tabindex="7" aria-controls="style-3" rowspan="1" colspan="1"
style="width: 51.625px;">Action</th>
</tr>
@@ -59,17 +61,18 @@
<tr role="row">
<td class="text-center"> {{withdrawal_obj.id}} </td>
<td>{{withdrawal_obj.principal}}</td>
<td>{{withdrawal_obj.coins}}</td>
<!-- <td>{{withdrawal_obj.coins}}</td> -->
<td>{{withdrawal_obj.amount}}</td>
<td>{{withdrawal_obj.token}}</td>
<td>{{withdrawal_obj.status}}</td>
<td>{{withdrawal_obj.created_on}}</td>
<td class="text-center">
<!-- <td class="text-center">
<button type="button" class="btn btn-info mb-2 me-4"
data-bs-toggle="modal" data-bs-target="#tabsModalMessageReply"
onclick="MessageModal('{{withdrawal_obj.notes}}','{{withdrawal_obj.reply}}')">
View
</button>
</td>
</td> -->
<td class="text-center">
<button type="button" class="btn btn-success mb-2 me-4"
data-bs-toggle="modal" data-bs-target="#replyFormModal"