referral tracking, wallet, transaction
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import re
|
||||
|
||||
from django.utils import timezone
|
||||
from django.contrib.auth.hashers import make_password
|
||||
from rest_framework import serializers
|
||||
|
||||
@@ -13,6 +13,7 @@ from manage_referrals.models import (
|
||||
ReferralRecord,
|
||||
)
|
||||
from goodtimes import constants, date_utils
|
||||
from manage_subscriptions.models import PrincipalSubscription, SubscriptionStatus
|
||||
|
||||
|
||||
def clean_phone(number: str):
|
||||
@@ -138,6 +139,7 @@ class ProfileSerializer(serializers.ModelSerializer):
|
||||
email = serializers.CharField(read_only=True)
|
||||
invite_count = serializers.SerializerMethodField(read_only=True)
|
||||
principal_type_name = serializers.SerializerMethodField(read_only=True)
|
||||
has_active_subscription = serializers.SerializerMethodField(read_only=True)
|
||||
|
||||
class Meta:
|
||||
model = IAmPrincipal
|
||||
@@ -150,6 +152,7 @@ class ProfileSerializer(serializers.ModelSerializer):
|
||||
"email",
|
||||
"invite_count",
|
||||
"register_complete",
|
||||
"has_active_subscription",
|
||||
]
|
||||
|
||||
def update(self, instance, validated_data):
|
||||
@@ -162,10 +165,7 @@ class ProfileSerializer(serializers.ModelSerializer):
|
||||
|
||||
def get_invite_count(self, obj):
|
||||
if obj:
|
||||
principal_type = self.context.get(
|
||||
"principal_type"
|
||||
) # Retrieve the principal_type from the context
|
||||
return ReferralRecord.get_invite_count(obj, principal_type)
|
||||
return ReferralRecord.get_invite_count(obj)
|
||||
return 0
|
||||
|
||||
def get_principal_type_name(self, obj):
|
||||
@@ -177,6 +177,19 @@ class ProfileSerializer(serializers.ModelSerializer):
|
||||
return request.build_absolute_uri(image_field.url)
|
||||
return ""
|
||||
|
||||
def get_has_active_subscription(self, obj):
|
||||
today = timezone.now().date()
|
||||
try:
|
||||
last_active_subscription = PrincipalSubscription.objects.filter(
|
||||
principal=obj,
|
||||
cancelled=False,
|
||||
status=SubscriptionStatus.ACTIVE,
|
||||
end_date__gte=today,
|
||||
).latest("end_date")
|
||||
return True # If the query does not raise DoesNotExist, return True
|
||||
except PrincipalSubscription.DoesNotExist:
|
||||
return False # If no matching subscription is found, return False
|
||||
|
||||
def to_representation(self, instance):
|
||||
data = super().to_representation(instance)
|
||||
request = self.context.get("request")
|
||||
|
||||
@@ -709,7 +709,6 @@ class GoogleLoginAPIView(APIView):
|
||||
|
||||
principal, created = IAmPrincipal.objects.update_or_create(
|
||||
email=email,
|
||||
username=email,
|
||||
defaults=defaults,
|
||||
)
|
||||
principal_type_instance = IAmPrincipalType.objects.get(name=principal_type)
|
||||
@@ -718,6 +717,7 @@ class GoogleLoginAPIView(APIView):
|
||||
print("New Created")
|
||||
default_password = f"GTMES{email[::-1]}"
|
||||
principal.set_password(default_password)
|
||||
principal.username = email
|
||||
principal.principal_type = principal_type_instance # Assuming principal_type should only be set on creation
|
||||
principal.principal_source = google_source
|
||||
principal.save()
|
||||
|
||||
@@ -1,5 +1,10 @@
|
||||
from django import forms
|
||||
from .models import ReferralRecord, ReferralRecordReward, GoodTimeCoins
|
||||
from .models import (
|
||||
ReferralRecord,
|
||||
ReferralRecordReward,
|
||||
GoodTimeCoins,
|
||||
ReferralTracking,
|
||||
)
|
||||
|
||||
|
||||
class ReferralRecordForm(forms.ModelForm):
|
||||
@@ -35,7 +40,32 @@ class GoodTimeCoinsForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = GoodTimeCoins
|
||||
fields = ["value_in_pound", "comments"]
|
||||
# widgets = {
|
||||
# "start_date": forms.DateInput(attrs={"type": "date"}),
|
||||
# "end_date": forms.DateInput(attrs={"type": "date"}),
|
||||
# }
|
||||
|
||||
|
||||
class ReferralTrackingForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = ReferralTracking
|
||||
fields = [
|
||||
"referral_record",
|
||||
"referrer_subscription_id",
|
||||
"referred_subscription_id",
|
||||
"is_referrer_subscribed",
|
||||
"ip_address",
|
||||
"user_agent",
|
||||
"device_model",
|
||||
]
|
||||
widgets = {
|
||||
"referral_record": forms.Select(attrs={"class": "form-control"}),
|
||||
"referrer_subscription_id": forms.NumberInput(
|
||||
attrs={"class": "form-control"}
|
||||
),
|
||||
"referred_subscription_id": forms.NumberInput(
|
||||
attrs={"class": "form-control"}
|
||||
),
|
||||
"is_referrer_subscribed": forms.CheckboxInput(
|
||||
attrs={"class": "form-check-input"}
|
||||
),
|
||||
"ip_address": forms.TextInput(attrs={"class": "form-control"}),
|
||||
"user_agent": forms.TextInput(attrs={"class": "form-control"}),
|
||||
"device_model": forms.TextInput(attrs={"class": "form-control"}),
|
||||
}
|
||||
|
||||
@@ -117,15 +117,15 @@ class ReferralRecord(BaseModel):
|
||||
return f"Referral ID: {self.id}, Referrar name: {self.referrer_principal.first_name}, Type: {self.principal_type.name}"
|
||||
|
||||
@classmethod
|
||||
def filter_invite_records(cls, referrer_principal, principal_type):
|
||||
def filter_invite_records(cls, referrer_principal):
|
||||
record_instance = cls.objects.filter(
|
||||
referrer_principal=referrer_principal, principal_type__name=principal_type
|
||||
referrer_principal=referrer_principal,
|
||||
)
|
||||
return record_instance
|
||||
|
||||
@classmethod
|
||||
def get_invite_count(cls, referrer_principal, principal_type):
|
||||
filter_record = cls.filter_invite_records(referrer_principal, principal_type)
|
||||
def get_invite_count(cls, referrer_principal):
|
||||
filter_record = cls.filter_invite_records(referrer_principal)
|
||||
return filter_record.count()
|
||||
|
||||
|
||||
|
||||
@@ -67,4 +67,21 @@ urlpatterns = [
|
||||
views.GTCoinsDeleteView.as_view(),
|
||||
name="coin_delete",
|
||||
),
|
||||
# Referral Tracking
|
||||
path("track/list/", views.ReferralTrackingView.as_view(), name="track_list"),
|
||||
# path(
|
||||
# "track/add/",
|
||||
# views.ReferralTrackingCreateOrUpdateView.as_view(),
|
||||
# name="track_add",
|
||||
# ),
|
||||
path(
|
||||
"track/edit/<int:pk>/",
|
||||
views.ReferralTrackingCreateOrUpdateView.as_view(),
|
||||
name="track_edit",
|
||||
),
|
||||
path(
|
||||
"track/delete/<int:pk>",
|
||||
views.ReferralTrackingDeleteView.as_view(),
|
||||
name="track_delete",
|
||||
),
|
||||
]
|
||||
|
||||
@@ -9,8 +9,14 @@ from manage_referrals.forms import (
|
||||
ReferralRecordForm,
|
||||
ReferralRecordRewardForm,
|
||||
GoodTimeCoinsForm,
|
||||
ReferralTrackingForm,
|
||||
)
|
||||
from manage_referrals.models import (
|
||||
ReferralRecord,
|
||||
ReferralRecordReward,
|
||||
GoodTimeCoins,
|
||||
ReferralTracking,
|
||||
)
|
||||
from manage_referrals.models import ReferralRecord, ReferralRecordReward, GoodTimeCoins
|
||||
from django.contrib import messages
|
||||
|
||||
|
||||
@@ -336,3 +342,106 @@ class GTCoinsDeleteView(LoginRequiredMixin, generic.View):
|
||||
messages.success(request, self.error_message)
|
||||
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class ReferralTrackingCreateOrUpdateView(LoginRequiredMixin, generic.View):
|
||||
# Set the page_name and resource
|
||||
page_name = resource_action.RESOURCE_MANAGE_REFERRALS
|
||||
resource = resource_action.RESOURCE_MANAGE_REFERRALS
|
||||
|
||||
# Initialize the action as ACTION_CREATE (can change based on logic)
|
||||
action = resource_action.ACTION_CREATE # Default action
|
||||
|
||||
template_name = "manage_referrals/track_add.html"
|
||||
model = ReferralTracking
|
||||
form_class = ReferralTrackingForm
|
||||
success_url = reverse_lazy("manage_referrals:track_list")
|
||||
error_message = "An error occurred while saving the data."
|
||||
|
||||
# Determine the success message dynamically based on whether it's an update or create
|
||||
def get_success_message(self):
|
||||
self.success_message = (
|
||||
constants.RECORD_CREATED if not self.object else constants.RECORD_UPDATED
|
||||
)
|
||||
return self.success_message
|
||||
|
||||
# Get the object (if exists) based on URL parameter 'pk'
|
||||
def get_object(self):
|
||||
pk = self.kwargs.get("pk")
|
||||
return get_object_or_404(self.model, pk=pk) if pk else None
|
||||
|
||||
# Add page_name and operation to the context
|
||||
def get_context_data(self, **kwargs):
|
||||
context = {
|
||||
"page_name": self.page_name,
|
||||
"operation": "Add" if not self.object else "Edit",
|
||||
}
|
||||
context.update(kwargs) # Include any additional context data passed to the view
|
||||
return context
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
if self.object is not None:
|
||||
self.action = resource_action.ACTION_UPDATE
|
||||
print("get method of article is called")
|
||||
form = self.form_class(instance=self.object)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
|
||||
def post(self, request, args, *kwargs):
|
||||
self.object = self.get_object()
|
||||
|
||||
# If an object is found, change action to ACTION_UPDATE
|
||||
if self.object is not None:
|
||||
self.action = resource_action.ACTION_UPDATE
|
||||
print("post method is called")
|
||||
form = self.form_class(request.POST, request.FILES, instance=self.object)
|
||||
print("request with files", request.FILES)
|
||||
if not form.is_valid():
|
||||
print(form.errors)
|
||||
context = self.get_context_data(form=form)
|
||||
return render(request, self.template_name, context=context)
|
||||
form.save()
|
||||
messages.success(self.request, self.get_success_message())
|
||||
return redirect(self.success_url)
|
||||
|
||||
|
||||
class ReferralTrackingView(LoginRequiredMixin, generic.ListView):
|
||||
page_name = resource_action.RESOURCE_MANAGE_REFERRALS
|
||||
resource = resource_action.RESOURCE_MANAGE_REFERRALS
|
||||
action = resource_action.ACTION_READ
|
||||
model = ReferralTracking
|
||||
template_name = "manage_referrals/track_list.html"
|
||||
context_object_name = "tracks"
|
||||
|
||||
def get_queryset(self):
|
||||
return super().get_queryset().filter(active=True, deleted=False)
|
||||
|
||||
def get_context_data(self, **kwargs):
|
||||
context = super().get_context_data(**kwargs)
|
||||
context["page_name"] = self.page_name
|
||||
return context
|
||||
|
||||
|
||||
class ReferralTrackingDeleteView(LoginRequiredMixin, generic.View):
|
||||
page_name = resource_action.RESOURCE_MANAGE_REFERRALS
|
||||
resource = resource_action.RESOURCE_MANAGE_REFERRALS
|
||||
action = resource_action.ACTION_DELETE
|
||||
model = ReferralTracking
|
||||
success_url = reverse_lazy("manage_referrals:track_list")
|
||||
success_message = constants.RECORD_DELETED
|
||||
error_message = constants.RECORD_NOT_FOUND
|
||||
|
||||
def get(self, request, pk):
|
||||
try:
|
||||
type_obj = self.model.objects.get(id=pk)
|
||||
type_obj.deleted = True
|
||||
type_obj.active = False
|
||||
type_obj.save()
|
||||
messages.success(request, self.success_message)
|
||||
except self.model.DoesNotExist:
|
||||
messages.success(request, self.error_message)
|
||||
|
||||
return redirect(self.success_url)
|
||||
|
||||
@@ -8,4 +8,5 @@ from rest_framework_simplejwt.views import (
|
||||
urlpatterns = [
|
||||
path('buy-subscription/', views.CreatePrincipalSubscriptionApi.as_view(), name='buy_subscription'),
|
||||
path('test-webhook/', views.StripeWebhookTest.as_view(), name='webhook_test'),
|
||||
path('check-subscription/', views.LastActiveSubscriptionView.as_view(), name='check_subscription'),
|
||||
]
|
||||
|
||||
@@ -10,7 +10,11 @@ import stripe
|
||||
from accounts.models import IAmPrincipal
|
||||
import json
|
||||
from goodtimes import constants, services
|
||||
from manage_subscriptions.models import Subscription, PrincipalSubscription
|
||||
from manage_subscriptions.models import (
|
||||
Subscription,
|
||||
PrincipalSubscription,
|
||||
SubscriptionStatus,
|
||||
)
|
||||
from goodtimes.utils import ApiResponse
|
||||
from accounts.resource_action import (
|
||||
PRINCIPAL_TYPE_EVENT_USER,
|
||||
@@ -206,3 +210,32 @@ class StripeWebhookTest(APIView):
|
||||
message="Error processing event",
|
||||
errors=str(e),
|
||||
)
|
||||
|
||||
|
||||
class LastActiveSubscriptionView(APIView):
|
||||
authentication_classes = [JWTAuthentication]
|
||||
permission_classes = [IsAuthenticated]
|
||||
|
||||
def get(self, request, *args, **kwargs):
|
||||
today = timezone.now().date()
|
||||
try:
|
||||
last_active_subscription = PrincipalSubscription.objects.filter(
|
||||
principal=request.user,
|
||||
cancelled=False,
|
||||
status=SubscriptionStatus.ACTIVE,
|
||||
end_date__gte=today,
|
||||
).latest("end_date")
|
||||
|
||||
serializer = PrincipalSubscriptionSerializer(last_active_subscription)
|
||||
return ApiResponse.success(
|
||||
status=status.HTTP_200_OK,
|
||||
message=constants.SUCCESS,
|
||||
data=serializer.data,
|
||||
)
|
||||
|
||||
except PrincipalSubscription.DoesNotExist:
|
||||
return ApiResponse.error(
|
||||
status=status.HTTP_404_NOT_FOUND,
|
||||
message="No Active Subscription Found",
|
||||
errors="No Active Subscription Found",
|
||||
)
|
||||
|
||||
@@ -39,6 +39,7 @@ urlpatterns = [
|
||||
views.PlanDeleteView.as_view(),
|
||||
name="plan_delete",
|
||||
),
|
||||
# Principal Subscription
|
||||
path("principal_subscription/list/", views.PrincipalSubscriptionView.as_view(), name="principal_subscriptions_list"),
|
||||
path(
|
||||
"principal_subscription/add/",
|
||||
|
||||
52
manage_wallets/forms.py
Normal file
52
manage_wallets/forms.py
Normal file
@@ -0,0 +1,52 @@
|
||||
from django import forms
|
||||
from .models import Wallet, Transaction
|
||||
|
||||
|
||||
class WalletForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Wallet
|
||||
fields = [
|
||||
"principal",
|
||||
"balance",
|
||||
"deposit",
|
||||
"earnings",
|
||||
"coins",
|
||||
"withdrawal_balance",
|
||||
]
|
||||
widgets = {
|
||||
"principal": forms.Select(attrs={"class": "form-control"}),
|
||||
"balance": forms.NumberInput(attrs={"class": "form-control"}),
|
||||
"deposit": forms.NumberInput(attrs={"class": "form-control"}),
|
||||
"earnings": forms.NumberInput(attrs={"class": "form-control"}),
|
||||
"coins": forms.NumberInput(attrs={"class": "form-control"}),
|
||||
"withdrawal_balance": forms.NumberInput(attrs={"class": "form-control"}),
|
||||
}
|
||||
|
||||
|
||||
class TransactionForm(forms.ModelForm):
|
||||
class Meta:
|
||||
model = Transaction
|
||||
fields = [
|
||||
"principal",
|
||||
"principal_subscription",
|
||||
"transaction_type",
|
||||
"payment_method",
|
||||
"transaction_status",
|
||||
"amount",
|
||||
"comment",
|
||||
"order_id",
|
||||
"product_id",
|
||||
"reference_id",
|
||||
]
|
||||
widgets = {
|
||||
"principal": forms.Select(attrs={"class": "form-control"}),
|
||||
"principal_subscription": forms.Select(attrs={"class": "form-control"}),
|
||||
"transaction_type": forms.Select(attrs={"class": "form-control"}),
|
||||
"payment_method": forms.Select(attrs={"class": "form-control"}),
|
||||
"transaction_status": forms.Select(attrs={"class": "form-control"}),
|
||||
"amount": forms.NumberInput(attrs={"class": "form-control"}),
|
||||
"comment": forms.TextInput(attrs={"class": "form-control"}),
|
||||
"order_id": forms.TextInput(attrs={"class": "form-control"}),
|
||||
"product_id": forms.TextInput(attrs={"class": "form-control"}),
|
||||
"reference_id": forms.TextInput(attrs={"class": "form-control"}),
|
||||
}
|
||||
@@ -11,6 +11,6 @@ urlpatterns = [
|
||||
|
||||
|
||||
# for manage payment related url
|
||||
path('peyment/', views.PaymentListView.as_view(), name='payment_list'),
|
||||
path('payment/', views.PaymentListView.as_view(), name='payment_list'),
|
||||
|
||||
]
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Event</h3>
|
||||
<h3>{{operation}} {{page_title}}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Event Category</h3>
|
||||
<h3>{{operation}} {{page_title}}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Event</h3>
|
||||
<h3>{{operation}} {{page_title}}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
</button>
|
||||
-->
|
||||
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:reward_list' %}">Referral Rewards</a>
|
||||
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:track_list' %}">Referral Tracking</a>
|
||||
<a class="btn btn-primary mb-2" href="{% url 'manage_referrals:coin_list' %}">Good Time Coins</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
135
templates/manage_referrals/track_add.html
Normal file
135
templates/manage_referrals/track_add.html
Normal file
@@ -0,0 +1,135 @@
|
||||
{% extends 'layout/base_template.html' %}
|
||||
{% load static %}
|
||||
{% block stylesheet %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
|
||||
{% include "cdn_through_html/filepond_cdn_css.html" %}
|
||||
{% include "cdn_through_html/quill_cdn_css.html" %}
|
||||
{% include "cdn_through_html/tagify_cdn_css.html" %}
|
||||
{{form.media}}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row layout-top-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Referral Track</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
<i class="fa fa-arrow-left"></i>
|
||||
Back
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row layout-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="statbox widget box box-shadow">
|
||||
<div class="widget-content widget-content-area">
|
||||
|
||||
<form method="POST" enctype="multipart/form-data">
|
||||
{% csrf_token %}
|
||||
{% include 'includes/dynamic_template_form.html' with form=form %}
|
||||
<div class="mt-4 mb-0">
|
||||
<div class="d-grid"><button class="btn btn-primary btn-block" type="submit">Submit</button></div>
|
||||
</div>
|
||||
{% comment %} <div class="mb-3">
|
||||
<label for="title" class="form-label">Title</label>
|
||||
<input type="text" class="form-control" id="title" aria-describedby="title">
|
||||
<div id="emailHelp" class="form-text" style="color: grey;">We'll never share your email with anyone else.</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label class="form-label">Description</label>
|
||||
<div id="description"></div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="product-images">Image</label>
|
||||
<div class="multiple-file-upload">
|
||||
<div class="filepond--root filepond file-upload-multiple filepond--hopper" id="images" data-style-button-remove-item-position="left" data-style-button-process-item-position="right" data-style-load-indicator-position="right" data-style-progress-indicator-position="right" data-style-button-remove-item-align="false" style="height: 57px;"><input class="filepond--browser" type="file" id="filepond--browser-feeq8o6dj" name="filepond" aria-controls="filepond--assistant-feeq8o6dj" aria-labelledby="filepond--drop-label-feeq8o6dj" multiple=""><a class="filepond--credits" aria-hidden="true" href="https://pqina.nl/" target="_blank" rel="noopener noreferrer" style="transform: translateY(49px);">Powered by PQINA</a><div class="filepond--drop-label" style="transform: translate3d(0px, 0px, 0px); opacity: 1;"><label for="filepond--browser-feeq8o6dj" id="filepond--drop-label-feeq8o6dj" aria-hidden="true">Drag & Drop your files or <span class="filepond--label-action" tabindex="0">Browse</span></label></div><div class="filepond--list-scroller" style="transform: translate3d(0px, 41px, 0px);"><ul class="filepond--list" role="list"></ul></div><div class="filepond--panel filepond--panel-root" data-scalable="true"><div class="filepond--panel-top filepond--panel-root"></div><div class="filepond--panel-center filepond--panel-root" style="transform: translate3d(0px, 8px, 0px) scale3d(1, 0.41, 1);"></div><div class="filepond--panel-bottom filepond--panel-root" style="transform: translate3d(0px, 49px, 0px);"></div></div><span class="filepond--assistant" id="filepond--assistant-feeq8o6dj" role="status" aria-live="polite" aria-relevant="additions"></span><div class="filepond--drip"></div><fieldset class="filepond--data"></fieldset></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="mb-3">
|
||||
<label for="tags">Tags</label>
|
||||
<input id="tags" class="tags" value="">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Submit</button> {% endcomment %}
|
||||
</form>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
|
||||
{% include "cdn_through_html/filepond_cdn_js.html" %}
|
||||
{% include "cdn_through_html/quill_cdn_js.html" %}
|
||||
{% include "cdn_through_html/tagify_cdn_js.html" %}
|
||||
|
||||
|
||||
<script>
|
||||
/**
|
||||
* ===================================
|
||||
* Blog Description Editor
|
||||
* ===================================
|
||||
*/
|
||||
var quill = new Quill('#description', {
|
||||
modules: {
|
||||
toolbar: [
|
||||
[{ header: [1, 2, false] }],
|
||||
['bold', 'italic', 'underline'],
|
||||
['image', 'code-block']
|
||||
]
|
||||
},
|
||||
placeholder: 'Write description...',
|
||||
theme: 'snow' // or 'bubble'
|
||||
});
|
||||
|
||||
|
||||
/**
|
||||
* ====================
|
||||
* File Pond
|
||||
* ====================
|
||||
*/
|
||||
|
||||
// We want to preview images, so we register
|
||||
// the Image Preview plugin, We also register
|
||||
// exif orientation (to correct mobile image
|
||||
// orientation) and size validation, to prevent
|
||||
// large files from being added
|
||||
FilePond.registerPlugin(
|
||||
FilePondPluginImagePreview,
|
||||
FilePondPluginImageExifOrientation,
|
||||
FilePondPluginFileValidateSize,
|
||||
// FilePondPluginImageEdit
|
||||
);
|
||||
|
||||
// Select the file input and use
|
||||
// create() to turn it into a pond
|
||||
var ecommerce = FilePond.create(document.querySelector('.file-upload-multiple'));
|
||||
|
||||
|
||||
/**
|
||||
* =====================
|
||||
* Blog Tags
|
||||
* =====================
|
||||
*/
|
||||
// The DOM element you wish to replace with Tagify
|
||||
var input = document.querySelector('#id_tags');
|
||||
|
||||
// initialize Tagify on the above input node reference
|
||||
new Tagify(input,{
|
||||
originalInputValueFormat: valuesArr => valuesArr.map(item => item.value).join(', ')
|
||||
})
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
140
templates/manage_referrals/track_list.html
Normal file
140
templates/manage_referrals/track_list.html
Normal file
@@ -0,0 +1,140 @@
|
||||
{% extends 'layout/base_template.html' %}
|
||||
{% load static %}
|
||||
{% block stylesheet %}
|
||||
<!-- include required css cdn link through html here -->
|
||||
{% include "cdn_through_html/datatable_cdn_css.html" %}
|
||||
|
||||
{% endblock %}
|
||||
|
||||
{% block content %}
|
||||
|
||||
<div class="row layout-top-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="row">
|
||||
<div class="col-sm-6">
|
||||
<h3>Referral Tracking</h3>
|
||||
</div>
|
||||
<div class="col-sm-6 text-md-end">
|
||||
<!--
|
||||
<button class="btn btn-dark mb-2 me-md-4" onclick="history.back()">
|
||||
<i class="fa fa-arrow-left"></i>
|
||||
Back
|
||||
</button>
|
||||
-->
|
||||
<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:coin_list' %}">Good Time Coins</a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="row layout-spacing">
|
||||
<div class="col-lg-12">
|
||||
<div class="statbox widget box box-shadow">
|
||||
<div class="widget-content widget-content-area">
|
||||
<div id="style-3_wrapper" class="dataTables_wrapper container-fluid dt-bootstrap4 no-footer">
|
||||
<div class="table-responsive">
|
||||
<table id="style-3" class="table style-3 dt-table-hover dataTable no-footer" role="grid"
|
||||
aria-describedby="style-3_info">
|
||||
<thead>
|
||||
<tr role="row">
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Record Id </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Referral Record </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Referrer Subscription </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Referred Subscription </th>
|
||||
<th class="checkbox-column sorting_asc" tabindex="0" aria-controls="style-3"
|
||||
aria-sort="ascending" style="width: 69.2656px;"> Referrer Subscription Active </th>
|
||||
<th class="sorting" tabindex="7" aria-controls="style-3"
|
||||
style="width: 79.7969px;">Active</th>
|
||||
<th class="dt-no-sorting sorting" tabindex="8" aria-controls="style-3"
|
||||
style="width: 100.625px;">Action</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
{% for data_obj in tracks %}
|
||||
<tr role="row">
|
||||
<td class="checkbox-column text-center sorting_1">{{data_obj.id}}</td>
|
||||
<td>{{data_obj.referral_record}}</td>
|
||||
<td>{{data_obj.referrer_subscription_id}}</td>
|
||||
<td>{{data_obj.referred_subscription_id}}</td>
|
||||
<td>{{data_obj.is_referrer_subscribed}}</td>
|
||||
<td class="text-center">
|
||||
<span
|
||||
class="shadow-none badge {% if data_obj.active %}badge-primary{% else %}badge-danger{% endif %}">{{data_obj.active}}</span>
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<ul class="table-controls">
|
||||
<li><a href="{% url 'manage_referrals:track_edit' data_obj.id %}"
|
||||
class="bs-tooltip" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" title="" data-original-title="Edit"
|
||||
data-bs-original-title="Edit" aria-label="Edit"><svg
|
||||
xmlns="http://www.w3.org/2000/svg" width="24"
|
||||
height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
class="feather feather-edit-2 p-1 br-8 mb-1">
|
||||
<path
|
||||
d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z">
|
||||
</path>
|
||||
</svg></a></li>
|
||||
<li><a href="{% url 'manage_referrals:track_delete' data_obj.id %}"
|
||||
class="bs-tooltip" data-bs-toggle="tooltip"
|
||||
data-bs-placement="top" title=""
|
||||
data-original-title="Delete" data-bs-original-title="Delete"
|
||||
aria-label="Delete"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
width="24" height="24" viewBox="0 0 24 24" fill="none"
|
||||
stroke="currentColor" stroke-width="2"
|
||||
stroke-linecap="round" stroke-linejoin="round"
|
||||
class="feather feather-trash p-1 br-8 mb-1">
|
||||
<polyline points="3 6 5 6 21 6"></polyline>
|
||||
<path
|
||||
d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2">
|
||||
</path>
|
||||
</svg></a></li>
|
||||
</ul>
|
||||
</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{% endblock content %}
|
||||
|
||||
{% block javascript %}
|
||||
<!-- include required js cdn link through html here -->
|
||||
{% include "cdn_through_html/datatable_cdn_js.html" %}
|
||||
|
||||
<script>
|
||||
c3 = $('#style-3').DataTable({
|
||||
"dom": "<'dt--top-section'<'row'<'col-12 col-sm-6 d-flex justify-content-sm-start justify-content-center'l><'col-12 col-sm-6 d-flex justify-content-sm-end justify-content-center mt-sm-0 mt-3'f>>>" +
|
||||
"<'table-responsive'tr>" +
|
||||
"<'dt--bottom-section d-sm-flex justify-content-sm-between text-center'<'dt--pages-count mb-sm-0 mb-3'i><'dt--pagination'p>>",
|
||||
"oLanguage": {
|
||||
"oPaginate": { "sPrevious": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-left"><line x1="19" y1="12" x2="5" y2="12"></line><polyline points="12 19 5 12 12 5"></polyline></svg>', "sNext": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-arrow-right"><line x1="5" y1="12" x2="19" y2="12"></line><polyline points="12 5 19 12 12 19"></polyline></svg>' },
|
||||
"sInfo": "Showing page PAGE of _PAGES_",
|
||||
"sSearch": '<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="feather feather-search"><circle cx="11" cy="11" r="8"></circle><line x1="21" y1="21" x2="16.65" y2="16.65"></line></svg>',
|
||||
"sSearchPlaceholder": "Search...",
|
||||
"sLengthMenu": "Results : _MENU_",
|
||||
},
|
||||
"stripeClasses": [],
|
||||
"lengthMenu": [5, 10, 20, 50],
|
||||
"pageLength": 10
|
||||
});
|
||||
|
||||
multiCheck(c3);
|
||||
|
||||
</script>
|
||||
{% endblock %}
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Plan</h3>
|
||||
<h3>{{operation}} {{page_name}}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Principal Subscription</h3>
|
||||
<h3>{{operation}} {{page_name}}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
|
||||
@@ -85,7 +85,7 @@
|
||||
</td>
|
||||
<td class="text-center">
|
||||
<ul class="table-controls">
|
||||
<li><a href="{% url 'manage_subscriptions:subscription_edit' data_obj.id %}" class="bs-tooltip"
|
||||
<li><a href="{% url 'manage_subscriptions:principal_subscription_edit' data_obj.id %}" class="bs-tooltip"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title=""
|
||||
data-original-title="Edit" data-bs-original-title="Edit"
|
||||
aria-label="Edit"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
@@ -97,7 +97,7 @@
|
||||
d="M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z">
|
||||
</path>
|
||||
</svg></a></li>
|
||||
<li><a href="{% url 'manage_subscriptions:subscription_delete' data_obj.id %}" class="bs-tooltip"
|
||||
<li><a href="{% url 'manage_subscriptions:principal_subscription_delete' data_obj.id %}" class="bs-tooltip"
|
||||
data-bs-toggle="tooltip" data-bs-placement="top" title=""
|
||||
data-original-title="Delete" data-bs-original-title="Delete"
|
||||
aria-label="Delete"><svg xmlns="http://www.w3.org/2000/svg"
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
<div class="col-lg-12">
|
||||
<div class="row mb-2">
|
||||
<div class="col">
|
||||
<h3>Add Principal Subscription</h3>
|
||||
<h3>{{operation}} {{page_name}}</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
<button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
<h3>Manage Payment</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
{% comment %} <button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
<i class="fa fa-arrow-left"></i>
|
||||
Back
|
||||
</button> {% endcomment %}
|
||||
{% comment %} <a class="btn btn-primary mb-2 me-4" href="{% url 'manage_cms:newsletter_add' %}">Add Newsletter</a> {% endcomment %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -64,12 +60,16 @@
|
||||
<tr role="row">
|
||||
<td class="checkbox-column text-center sorting_1">{{transaction_obj.id}}</td>
|
||||
|
||||
<td>{{transaction_obj.principal.phone_no}}</td>
|
||||
<td>{{transaction_obj.principal_type}}</td>
|
||||
<td>{{transaction_obj.get_transaction_type_display}}</td>
|
||||
<td>{{transaction_obj.get_transaction_status_display}}</td>
|
||||
<td>{{transaction_obj.principal}}</td>
|
||||
<td>{{transaction_obj.principal_subscription}}</td>
|
||||
<td>{{transaction_obj.transaction_type}}</td>
|
||||
<td>{{transaction_obj.payment_method}}</td>
|
||||
<td>{{transaction_obj.transaction_status}}</td>
|
||||
<td>{{transaction_obj.amount}}</td>
|
||||
<td>{{transaction_obj.comment}}</td>
|
||||
<td>{{transaction_obj.order_id}}</td>
|
||||
<td>{{transaction_obj.product_id}}</td>
|
||||
<td>{{transaction_obj.reference_id}}</td>
|
||||
|
||||
|
||||
</tr>
|
||||
|
||||
@@ -15,11 +15,7 @@
|
||||
<h3>Manage Wallet</h3>
|
||||
</div>
|
||||
<div class="col text-end">
|
||||
{% comment %} <button class="btn btn-dark mb-2 me-4" onclick="history.back()">
|
||||
<i class="fa fa-arrow-left"></i>
|
||||
Back
|
||||
</button> {% endcomment %}
|
||||
{% comment %} <a class="btn btn-primary mb-2 me-4" href="{% url 'manage_cms:newsletter_add' %}">Add Newsletter</a> {% endcomment %}
|
||||
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -39,26 +35,23 @@
|
||||
style="width: 69.2656px;"> Record Id </th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1"
|
||||
colspan="1" aria-label="Image: activate to sort column ascending"
|
||||
style="width: 44.2344px;">User</th>
|
||||
style="width: 44.2344px;">Principal</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
aria-label="First Name: activate to sort column ascending"
|
||||
style="width: 79.7969px;">Player Balance</th>
|
||||
style="width: 79.7969px;">Balance</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
aria-label="Last Name: activate to sort column ascending"
|
||||
style="width: 77.3281px;">Player Deposit</th>
|
||||
style="width: 77.3281px;">Deposit</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
aria-label="Email: activate to sort column ascending"
|
||||
style="width: 143.516px;">Player Bonus</th>
|
||||
style="width: 143.516px;">Earnings</th>
|
||||
<th class="sorting" tabindex="0" aria-controls="style-3" rowspan="1" colspan="1"
|
||||
aria-label="Mobile No.: activate to sort column ascending"
|
||||
style="width: 98.875px;">Merchant Balance</th>
|
||||
<th class="text-center sorting" tabindex="0" aria-controls="style-3" rowspan="1"
|
||||
colspan="1" aria-label="Status: activate to sort column ascending"
|
||||
style="width: 76.625px;">Merchant Deposit</th>
|
||||
style="width: 98.875px;">Coins</th>
|
||||
<th class="text-center dt-no-sorting sorting" tabindex="0"
|
||||
aria-controls="style-3" rowspan="1" colspan="1"
|
||||
aria-label="Action: activate to sort column ascending"
|
||||
style="width: 51.625px;">Merchant Bonus</th>
|
||||
style="width: 51.625px;">Withdrawal Balance</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@@ -67,14 +60,12 @@
|
||||
<tr role="row">
|
||||
<td class="checkbox-column text-center sorting_1">{{wallet_obj.id}}</td>
|
||||
|
||||
<td>{{wallet_obj.principal.phone_no}}</td>
|
||||
<td>{{wallet_obj.player_balance}}</td>
|
||||
<td>{{wallet_obj.player_deposit}}</td>
|
||||
<td>{{wallet_obj.player_bonus}}</td>
|
||||
<td>{{wallet_obj.merchant_balance}}</td>
|
||||
<td>{{wallet_obj.merchant_deposit}}</td>
|
||||
<td>{{wallet_obj.merchant_bonus}}</td>
|
||||
|
||||
<td>{{wallet_obj.principal}}</td>
|
||||
<td>{{wallet_obj.balance}}</td>
|
||||
<td>{{wallet_obj.deposit}}</td>
|
||||
<td>{{wallet_obj.earnings}}</td>
|
||||
<td>{{wallet_obj.coins}}</td>
|
||||
<td>{{wallet_obj.withdrawal_balance}}</td>
|
||||
</tr>
|
||||
{% endfor %}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user