diff --git a/accounts/context_processors.py b/accounts/context_processors.py index 97abd9b..6166662 100644 --- a/accounts/context_processors.py +++ b/accounts/context_processors.py @@ -37,6 +37,7 @@ def compute_resource_action_constants(): 'RESOURCE_MANAGE_CMS': resource_action.RESOURCE_MANAGE_CMS, 'RESOURCE_MANAGE_REPORTS': resource_action.RESOURCE_MANAGE_REPORTS, 'RESOURCE_MANAGE_SUBSCRIPTIONS': resource_action.RESOURCE_MANAGE_SUBSCRIPTIONS, + 'RESOURCE_MANAGE_NOTIFICATIONS': resource_action.RESOURCE_MANAGE_NOTIFICATIONS, 'RESOURCE_MANAGE_REFERRALS': resource_action.RESOURCE_MANAGE_REFERRALS, 'RESOURCE_MANAGE_FEEDBACK': resource_action.RESOURCE_MANAGE_FEEDBACK, 'RESOURCE_IAM_PRINCIPAL': resource_action.RESOURCE_IAM_PRINCIPAL, diff --git a/goodtimes/services.py b/goodtimes/services.py index 9baa415..9e2d3f0 100644 --- a/goodtimes/services.py +++ b/goodtimes/services.py @@ -15,7 +15,7 @@ from manage_referrals.models import ( ReferralTracking, ) from manage_subscriptions.models import PrincipalSubscription, Subscription -from manage_wallets.models import TransactionStatus, Wallet, Transaction +from manage_wallets.models import TransactionStatus, TransactionType, Wallet, Transaction from goodtimes.utils import CapacityError, RandomGenerator from manage_events.models import ( Event, @@ -281,6 +281,16 @@ class PaymentProcessingService: 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, + coin=1, + comment="Referral reward", + # Populate other fields as necessary, such as `order_id`, `product_id`, or `reference_id` if applicable + ) def _handle_failure(self): # Implement any necessary logic to handle a failed payment diff --git a/goodtimes/settings/base.py b/goodtimes/settings/base.py index ee10d58..497d1b7 100644 --- a/goodtimes/settings/base.py +++ b/goodtimes/settings/base.py @@ -64,7 +64,7 @@ LOCAL_APPS = [ "manage_referrals", "manage_cms", "manage_communications", # for contact us, and feedback - "manage_notifications", + "manage_notifications.apps.ManageNotificationsConfig", "chat", ] diff --git a/goodtimes/urls.py b/goodtimes/urls.py index be106e4..5414dc6 100644 --- a/goodtimes/urls.py +++ b/goodtimes/urls.py @@ -54,7 +54,8 @@ urlpatterns = [ path("api/subscriptions/", include("manage_subscriptions.api.urls")), path("notifications/", include("manage_notifications.urls")), - + path("api/notifications/", include("manage_notifications.api.urls")), + # path('', include('manage_notifications.urls')), # path('api/', include("accounts.api.urls")), ] diff --git a/manage_notifications/admin.py b/manage_notifications/admin.py index 8c38f3f..1def10c 100644 --- a/manage_notifications/admin.py +++ b/manage_notifications/admin.py @@ -1,3 +1,32 @@ from django.contrib import admin +from .models import PushNotification, IAmPrincipalNotificationSettings -# Register your models here. + +class PushNotificationAdmin(admin.ModelAdmin): + list_display = ( + "id", + "title", + "notification_category", + "principal_type", + "banner_image", + "message", + ) + search_fields = ("title", "notification_category", "principal_type") + list_filter = ("notification_category", "principal_type") + + +admin.site.register(PushNotification, PushNotificationAdmin) + + +class IAmPrincipalNotificationSettingsAdmin(admin.ModelAdmin): + list_display = ("id", "principal", "notification_category", "is_enabled") + search_fields = ("principal__first_name", "notification_category") + list_filter = ("notification_category", "is_enabled") + raw_id_fields = ( + "principal", + ) # This is useful if you have many users and a dropdown becomes impractical + + +admin.site.register( + IAmPrincipalNotificationSettings, IAmPrincipalNotificationSettingsAdmin +) diff --git a/manage_notifications/api/serializers.py b/manage_notifications/api/serializers.py new file mode 100644 index 0000000..55974d3 --- /dev/null +++ b/manage_notifications/api/serializers.py @@ -0,0 +1,13 @@ +from rest_framework import serializers +from manage_notifications.models import IAmPrincipalNotificationSettings, NotificationCategoryChoices + + +class IAmPrincipalNotificationSettingsSerializer(serializers.ModelSerializer): + notification_category_display = serializers.SerializerMethodField() + + def get_notification_category_display(self, obj): + return obj.get_notification_category_display() + + class Meta: + model = IAmPrincipalNotificationSettings + fields = ['id', 'notification_category', 'notification_category_display', 'is_enabled'] diff --git a/manage_notifications/api/urls.py b/manage_notifications/api/urls.py new file mode 100644 index 0000000..64466c0 --- /dev/null +++ b/manage_notifications/api/urls.py @@ -0,0 +1,17 @@ +from django.urls import path +from . import views + +app_name = "manage_notifications_api" + +urlpatterns = [ + path( + "toggle-notification-setting/", + views.NotificationSettingToggle.as_view(), + name="toggle-notification-setting", + ), + path( + "user-notifications/", + views.UserNotificationsAPIView.as_view(), + name="user-notifications", + ), +] diff --git a/manage_notifications/api/views.py b/manage_notifications/api/views.py new file mode 100644 index 0000000..329a3c0 --- /dev/null +++ b/manage_notifications/api/views.py @@ -0,0 +1,75 @@ +from rest_framework import status +from rest_framework.views import APIView +from django.conf import settings +from manage_notifications.api.serializers import ( + IAmPrincipalNotificationSettingsSerializer, +) +from manage_notifications.models import ( + IAmPrincipalNotificationSettings, + NotificationCategoryChoices, +) +from goodtimes import constants +from goodtimes.utils import ApiResponse +from rest_framework.permissions import IsAuthenticated +from rest_framework_simplejwt.authentication import JWTAuthentication + + +class NotificationSettingToggle(APIView): + authentication_classes = [JWTAuthentication] + permission_classes = [IsAuthenticated] + + def post(self, request, *args, **kwargs): + notification_category = request.data.get("notification_category") + enable = request.data.get("enable", True) + + if ( + not notification_category + or notification_category not in NotificationCategoryChoices.values + ): + return ApiResponse.error( + errors="Invalid notification category", + message=constants.FAILURE, + status=status.HTTP_400_BAD_REQUEST, + ) + + # Assuming IAmPrincipal model has a user field that relates to Django's User model + # You might need to adjust the query depending on your user-principal relationship + notification_setting, created = ( + IAmPrincipalNotificationSettings.objects.get_or_create( + principal=request.user, + notification_category=notification_category, + defaults={"is_enabled": enable}, + ) + ) + + if not created: + notification_setting.is_enabled = enable + notification_setting.save() + + return ApiResponse.success( + data=f"{notification_category}: { enable}.", + message=constants.SUCCESS, + status=status.HTTP_200_OK, + ) + + +class UserNotificationsAPIView(APIView): + authentication_classes = [JWTAuthentication] + permission_classes = [IsAuthenticated] + + def get(self, request, *args, **kwargs): + # Assuming your IAmPrincipal model has a user field linking to the User model + principal = request.user + notifications = ( + IAmPrincipalNotificationSettings.objects.filter(principal=principal) + .exclude(notification_category=NotificationCategoryChoices.GENERAL) + .exclude(notification_category=NotificationCategoryChoices.PROMOTIONS) + ) + serializer = IAmPrincipalNotificationSettingsSerializer( + notifications, many=True + ) + return ApiResponse.success( + data=serializer.data, + message=constants.SUCCESS, + status=status.HTTP_200_OK, + ) diff --git a/manage_notifications/apps.py b/manage_notifications/apps.py index ca7245b..d1deb6d 100644 --- a/manage_notifications/apps.py +++ b/manage_notifications/apps.py @@ -4,3 +4,7 @@ from django.apps import AppConfig class ManageNotificationsConfig(AppConfig): default_auto_field = "django.db.models.BigAutoField" name = "manage_notifications" + + def ready(self): + # Import signal handlers here + from . import signals diff --git a/manage_notifications/forms.py b/manage_notifications/forms.py index 7aec7e3..24ec1d3 100644 --- a/manage_notifications/forms.py +++ b/manage_notifications/forms.py @@ -1,5 +1,5 @@ from django import forms -from .models import PushNotification, NotificationCategory, PrincipalType +from .models import NotificationCategoryChoices, PushNotification class PushNotificationForm(forms.ModelForm): @@ -15,3 +15,11 @@ class PushNotificationForm(forms.ModelForm): widgets = { "message": forms.Textarea(attrs={"rows": 4}), } + + def __init__(self, *args, **kwargs): + super(PushNotificationForm, self).__init__(*args, **kwargs) + # Limit choices for notification_category to GENERAL and PROMOTIONS only + self.fields["notification_category"].choices = [ + (NotificationCategoryChoices.GENERAL, "General"), + (NotificationCategoryChoices.PROMOTIONS, "Promotions"), + ] diff --git a/manage_notifications/migrations/0002_alter_pushnotification_notification_category_and_more.py b/manage_notifications/migrations/0002_alter_pushnotification_notification_category_and_more.py new file mode 100644 index 0000000..8750a03 --- /dev/null +++ b/manage_notifications/migrations/0002_alter_pushnotification_notification_category_and_more.py @@ -0,0 +1,68 @@ +# Generated by Django 5.0.2 on 2024-03-13 19:07 + +import django.utils.timezone +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("manage_notifications", "0001_initial"), + ] + + operations = [ + migrations.AlterField( + model_name="pushnotification", + name="notification_category", + field=models.CharField( + choices=[ + ("general", "General"), + ("transaction", "Transaction"), + ("referral", "Referral"), + ("subscription", "Subscription"), + ("event", "Event"), + ("promotions", "Promotions"), + ], + max_length=50, + ), + ), + migrations.RemoveField( + model_name="notificationsettings", + name="category", + ), + migrations.RemoveField( + model_name="notificationsettings", + name="created_by", + ), + migrations.RemoveField( + model_name="notificationsettings", + name="modified_by", + ), + migrations.RemoveField( + model_name="iamprincipalnotificationsettings", + name="notification_setting", + ), + migrations.AddField( + model_name="iamprincipalnotificationsettings", + name="notification_category", + field=models.CharField( + choices=[ + ("general", "General"), + ("transaction", "Transaction"), + ("referral", "Referral"), + ("subscription", "Subscription"), + ("event", "Event"), + ("promotions", "Promotions"), + ], + default=django.utils.timezone.now, + max_length=50, + ), + preserve_default=False, + ), + migrations.DeleteModel( + name="NotificationCategory", + ), + migrations.DeleteModel( + name="NotificationSettings", + ), + ] diff --git a/manage_notifications/models.py b/manage_notifications/models.py index 0eabaaa..b7cde3a 100644 --- a/manage_notifications/models.py +++ b/manage_notifications/models.py @@ -1,16 +1,18 @@ 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_wallets.models import Wallet # Create your models here. -class NotificationCategory(BaseModel): - name = models.CharField(max_length=100) - - class Meta: - db_table = "notification_settings_category" - - def __str__(self) -> str: - return f"name : {self.name}" +class NotificationCategoryChoices(models.TextChoices): + GENERAL = "general", "General" + TRANSACTION = "transaction", "Transaction" + REFERRAL = "referral", "Referral" + SUBSCRIPTION = "subscription", "Subscription" + EVENT = "event", "Event" + PROMOTIONS = "promotions", "Promotions" class PrincipalType(models.TextChoices): @@ -21,10 +23,9 @@ class PrincipalType(models.TextChoices): class PushNotification(BaseModel): title = models.CharField(max_length=255) - notification_category = models.ForeignKey( - NotificationCategory, - on_delete=models.CASCADE, - related_name="push_category", + notification_category = models.CharField( + max_length=50, + choices=NotificationCategoryChoices.choices, ) banner_image = models.ImageField( upload_to="push_notification_images/", blank=True, null=True @@ -39,27 +40,13 @@ class PushNotification(BaseModel): return self.title -class NotificationSettings(BaseModel): - name = models.CharField(max_length=100) - category = models.ForeignKey( - NotificationCategory, - on_delete=models.CASCADE, - related_name="notification_category", - ) - - class Meta: - db_table = "notification_settings" - - def __str__(self) -> str: - return f"name: {self.name}" - - class IAmPrincipalNotificationSettings(BaseModel): principal = models.ForeignKey( IAmPrincipal, on_delete=models.CASCADE, related_name="notifications_principal" ) - notification_setting = models.ForeignKey( - NotificationSettings, on_delete=models.CASCADE + notification_category = models.CharField( + max_length=50, + choices=NotificationCategoryChoices.choices, ) is_enabled = models.BooleanField(default=True) @@ -67,4 +54,4 @@ class IAmPrincipalNotificationSettings(BaseModel): db_table = "iam_principal_notification_settings" def __str__(self): - return f"{self.principal.first_name} - {self.notification_setting.name}" + return f"{self.principal.first_name} - {self.notification_category}" diff --git a/manage_notifications/signals.py b/manage_notifications/signals.py new file mode 100644 index 0000000..2c89e3f --- /dev/null +++ b/manage_notifications/signals.py @@ -0,0 +1,16 @@ +from django.db.models.signals import post_save +from django.dispatch import receiver +from manage_wallets.models import Wallet +from .models import IAmPrincipalNotificationSettings, NotificationCategoryChoices + +@receiver(post_save, sender=Wallet) +def create_default_notification_settings(sender, instance, created, **kwargs): + if created: + principal = instance.principal + # Assuming NotificationCategoryChoices is a list of tuples as choices for the field + for category in NotificationCategoryChoices: + IAmPrincipalNotificationSettings.objects.create( + principal=principal, + notification_category=category.value, # Assuming category is a tuple and the value is at index 0 + is_enabled=True + ) diff --git a/manage_notifications/utils.py b/manage_notifications/utils.py index fb5db92..90b52b3 100644 --- a/manage_notifications/utils.py +++ b/manage_notifications/utils.py @@ -1,88 +1,69 @@ -# import requests -# from django.conf import settings - -# def onesignal_send_notification(notification): -# onesignal_app_id = settings.ONE_SIGNAL_APP_ID -# onesignal_rest_api_key = settings.ONE_SIGNAL_API_KEY - -# headers = { -# "Content-Type": "application/json; charset=utf-8", -# "Authorization": f"Basic {onesignal_rest_api_key}" -# } - -# # Determine player IDs based on notification_category and principal_type -# player_ids = [] - -# if notification.principal_type == PrincipalType.BOTH: -# # Get player IDs for both event_user and event_manager -# from .models import IAmPrincipal # Assuming your IAmPrincipal model is in the same app - -# event_user_principals = IAmPrincipal.objects.filter(iam_principal_type__name=PrincipalType.EVENT_USER) -# event_manager_principals = IAmPrincipal.objects.filter(iam_principal_type__name=PrincipalType.EVENT_MANAGER) - -# for principal in event_user_principals: -# # Assuming you have a field in IAmPrincipal that stores the player ID (e.g., 'one_signal_player_id') -# player_ids.append(principal.one_signal_player_id) - -# for principal in event_manager_principals: -# player_ids.append(principal.one_signal_player_id) - -# else: -# # Handle filtering for EVENT_USER or EVENT_MANAGER as needed (similar logic as above) - -# # Construct the notification payload -# data = { -# "app_id": onesignal_app_id, -# "headings": {"en": notification.title}, -# "contents": {"en": notification.message}, -# "include_player_ids": player_ids, # Include the filtered player IDs -# # Add other optional notification data according to OneSignal documentation -# } - -# if notification.banner_image: -# # Include image URL if provided (requires additional OneSignal configuration) -# data["large_icon"] = notification.banner_image.url # Assuming you have a URL property for the image field - -# # Send the notification request to OneSignal -# response = requests.post("https://onesignal.com/api/v1/notifications", headers=headers, json=data) - -# if response.status_code == 200: -# print("Notification sent successfully!") -# else: -# print(f"Error sending notification: {response.text}") - - +import json +import requests from onesignal_sdk.client import Client as OneSignalClient from django.conf import settings -from .models import IAmPrincipalNotificationSettings, NotificationSettings, IAmPrincipal +from .models import IAmPrincipalNotificationSettings, IAmPrincipal, PrincipalType -def send_notification(notification_type, title, message, image_url=None): +def onesignal_send_notification( + title, message, image_url="http://127.0.0.1:8000/", eligible_principals=None +): + onesignal_app_id = settings.ONE_SIGNAL_APP_ID + onesignal_rest_api_key = settings.ONE_SIGNAL_API_KEY + + headers = { + "Content-Type": "application/json; charset=utf-8", + "Authorization": f"Basic {onesignal_rest_api_key}", + } + + if not eligible_principals: + return None # Or handle this scenario as needed + + # Extract OneSignal player IDs + # player_ids = eligible_principals.values_list("player_id", flat=True) + + # Construct the notification payload + data = { + "app_id": onesignal_app_id, + "headings": {"en": title}, + "contents": {"en": message}, + "include_player_ids": eligible_principals, # Include the filtered player IDs + # Add other optional notification data according to OneSignal documentation + } + + if image_url: + # Include image URL if provided (requires additional OneSignal configuration) + data["large_icon"] = ( + str(image_url.url) + ) + + # data = json.dumps(data) + print("Data: ", data) + + # Send the notification request to OneSignal + response = requests.post( + "https://onesignal.com/api/v1/notifications", headers=headers, json=data + ) + + if response.status_code == 200: + print("Notification sent successfully!") + return True # Indicate success + else: + print(f"Error sending notification: {response.text}") + return False # Indicate failure + + +def send_notification(title, message, image_url=None, eligible_principals=None): # Initialize OneSignal client onesignal_client = OneSignalClient( app_id=settings.ONE_SIGNAL_APP_ID, rest_api_key=settings.ONE_SIGNAL_API_KEY ) - # Find all users who have enabled this type of notification - notification_setting = NotificationSettings.objects.filter( - name=notification_type - ).first() - if not notification_setting: - print("Notification type does not exist.") - return - - user_ids = IAmPrincipalNotificationSettings.objects.filter( - notification_setting=notification_setting, is_enabled=True - ).values_list("principal__id", flat=True) - - principals = ( - IAmPrincipal.objects.filter(id__in=user_ids) - .exclude(player_id__isnull=True) - .exclude(player_id__exact="") - ) + if not eligible_principals: + return None # Or handle this scenario as needed # Extract OneSignal player IDs - player_ids = principals.values_list("player_id", flat=True) + player_ids = eligible_principals.values_list("player_id", flat=True) # Prepare notification payload notification_payload = { @@ -99,3 +80,45 @@ def send_notification(notification_type, title, message, image_url=None): print(response.status_code, response.body) return response + + +def get_eligible_principals_for_notification(push_notification): + principal_type = push_notification.principal_type + notification_category = push_notification.notification_category + + if principal_type == PrincipalType.BOTH: + # If BOTH is selected, fetch users categorized under both EVENT_USER and EVENT_MANAGER + event_user_principals = IAmPrincipal.objects.filter( + principal_type__name=PrincipalType.EVENT_USER, + notifications_principal__notification_category=notification_category, + notifications_principal__is_enabled=True, + ) + + event_manager_principals = IAmPrincipal.objects.filter( + principal_type__name=PrincipalType.EVENT_MANAGER, + notifications_principal__notification_category=notification_category, + notifications_principal__is_enabled=True, + ) + + # Combine the QuerySets. Use | operator for OR query (union) and distinct() to avoid duplicates. + eligible_principals = ( + event_user_principals | event_manager_principals + ).distinct() + + elif principal_type == PrincipalType.EVENT_USER: + # Fetch only EVENT_USER principals + eligible_principals = IAmPrincipal.objects.filter( + principal_type__name=PrincipalType.EVENT_USER, + notifications_principal__notification_category=notification_category, + notifications_principal__is_enabled=True, + ) + + elif principal_type == PrincipalType.EVENT_MANAGER: + # Fetch only EVENT_MANAGER principals + eligible_principals = IAmPrincipal.objects.filter( + principal_type__name=PrincipalType.EVENT_MANAGER, + notifications_principal__notification_category=notification_category, + notifications_principal__is_enabled=True, + ) + + return eligible_principals diff --git a/manage_notifications/views.py b/manage_notifications/views.py index ca80a6c..618fb88 100644 --- a/manage_notifications/views.py +++ b/manage_notifications/views.py @@ -1,12 +1,18 @@ +import json from django.shortcuts import get_object_or_404, redirect, render from django.urls import reverse_lazy from django.views import generic from django.contrib.auth.mixins import LoginRequiredMixin from django.contrib import messages +from django.core.serializers import serialize from accounts import resource_action from goodtimes import constants from manage_notifications.forms import PushNotificationForm from manage_notifications.models import PushNotification +from manage_notifications.utils import ( + get_eligible_principals_for_notification, + onesignal_send_notification, +) # Create your views here. @@ -68,14 +74,43 @@ class PushNotificationsCreateOrUpdateView(LoginRequiredMixin, generic.View): print(form.errors) context = self.get_context_data(form=form) return render(request, self.template_name, context=context) + + push_notification = form.instance + eligible_principals = get_eligible_principals_for_notification( + push_notification + ) + print("eligible_principals: ", eligible_principals) + eligible_principals_json = serialize('json', eligible_principals) + eligible_principals_list = json.loads(eligible_principals_json) + player_ids = [principal['fields']['player_id'] for principal in eligible_principals_list] + # Send notification + title = push_notification.title + message = push_notification.message + image_url = push_notification.banner_image + onesignal_send_notification(title, message, image_url, player_ids) + print(onesignal_send_notification) + # if onesignal_send_notification( + # push_notification.title, + # push_notification.message, + # None, + # eligible_principals, + # ): + # form.save() + # messages.success(request, self.get_success_message()) + # return redirect(self.success_url) + # else: + # messages.error(request, "Failed to send notification. Form not saved.") + # 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()) + messages.success(request, self.get_success_message()) return redirect(self.success_url) class PushNotificationView(LoginRequiredMixin, generic.ListView): - page_name = resource_action.RESOURCE_MANAGE_EVENTS - resource = resource_action.RESOURCE_MANAGE_EVENTS + page_name = resource_action.RESOURCE_MANAGE_NOTIFICATIONS + resource = resource_action.RESOURCE_MANAGE_NOTIFICATIONS action = resource_action.ACTION_READ model = PushNotification template_name = "manage_notifications/notification_list.html" @@ -87,4 +122,4 @@ class PushNotificationView(LoginRequiredMixin, generic.ListView): def get_context_data(self, **kwargs): context = super().get_context_data(**kwargs) context["page_name"] = self.page_name - return context \ No newline at end of file + return context diff --git a/manage_subscriptions/views.py b/manage_subscriptions/views.py index 1935b46..40b58d6 100644 --- a/manage_subscriptions/views.py +++ b/manage_subscriptions/views.py @@ -415,7 +415,7 @@ def create_checkout_session(request): transaction = Transaction.objects.create( principal=request.user, principal_subscription=None, # Since the subscription is not created yet - transaction_type=TransactionType.DEPOSIT, # or PAYMENT, as applicable + transaction_type=TransactionType.PAYMENT, # or PAYMENT, as applicable payment_method=PaymentMethod.CARD, # Assuming CARD for this example transaction_status=TransactionStatus.INITIATE, amount=subscription.amount, # Fetching amount from the Subscription object diff --git a/manage_wallets/migrations/0005_transaction_coin_alter_transaction_payment_method_and_more.py b/manage_wallets/migrations/0005_transaction_coin_alter_transaction_payment_method_and_more.py new file mode 100644 index 0000000..97a80c4 --- /dev/null +++ b/manage_wallets/migrations/0005_transaction_coin_alter_transaction_payment_method_and_more.py @@ -0,0 +1,39 @@ +# Generated by Django 5.0.2 on 2024-03-13 19:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("manage_wallets", "0004_alter_wallet_coins"), + ] + + operations = [ + migrations.AddField( + model_name="transaction", + name="coin", + field=models.IntegerField(default=0), + ), + migrations.AlterField( + model_name="transaction", + name="payment_method", + field=models.CharField( + choices=[("card", "Card"), ("upi", "UPI"), ("coin", "Coin")], + max_length=10, + ), + ), + migrations.AlterField( + model_name="transaction", + name="transaction_type", + field=models.CharField( + choices=[ + ("payment", "Payment"), + ("deposit", "Deposit"), + ("withdraw", "Withdraw"), + ("credit", "Credit"), + ], + max_length=10, + ), + ), + ] diff --git a/manage_wallets/models.py b/manage_wallets/models.py index 285c30c..6de6c34 100644 --- a/manage_wallets/models.py +++ b/manage_wallets/models.py @@ -34,6 +34,7 @@ class TransactionType(models.TextChoices): PAYMENT = "payment", "Payment" DEPOSIT = "deposit", "Deposit" WITHDRAW = "withdraw", "Withdraw" + CREDIT = "credit", "Credit" class TransactionStatus(models.TextChoices): @@ -45,6 +46,7 @@ class TransactionStatus(models.TextChoices): class PaymentMethod(models.TextChoices): CARD = "card", "Card" UPI = "upi", "UPI" + COIN = "coin", "Coin" class Transaction(BaseModel): @@ -70,6 +72,7 @@ class Transaction(BaseModel): default=TransactionStatus.INITIATE, ) amount = models.DecimalField(max_digits=14, decimal_places=2, default=0.00) + coin = models.IntegerField(default=0) comment = models.CharField(max_length=200, null=True, blank=True) order_id = models.CharField(unique=True, max_length=255, null=True, blank=True) product_id = models.CharField(unique=True, max_length=255, null=True, blank=True) diff --git a/templates/elements/sidebar.html b/templates/elements/sidebar.html index 76ef3d9..7f5b227 100644 --- a/templates/elements/sidebar.html +++ b/templates/elements/sidebar.html @@ -173,15 +173,15 @@ -