diff --git a/eox_nelp/admin/__init__.py b/eox_nelp/admin/__init__.py index b16f2908..db65aaaa 100644 --- a/eox_nelp/admin/__init__.py +++ b/eox_nelp/admin/__init__.py @@ -5,3 +5,4 @@ from eox_nelp.admin.course_creators import * # noqa: F401 from eox_nelp.course_experience.admin import * # noqa: F401 from eox_nelp.notifications.admin import * # noqa: F401 +from eox_nelp.payment_notifications.admin import * # noqa: F401 diff --git a/eox_nelp/apps.py b/eox_nelp/apps.py index 14e3f751..78d04608 100644 --- a/eox_nelp/apps.py +++ b/eox_nelp/apps.py @@ -57,6 +57,12 @@ class EoxNelpConfig(AppConfig): 'dispatch_uid': 'enrollment_publisher_receiver', 'sender_path': 'common.djangoapps.student.models.CourseEnrollment', }, + { + 'receiver_func_name': 'update_payment_notifications', + 'signal_path': 'django.db.models.signals.post_save', + 'dispatch_uid': 'update_payment_notifications_receiver', + 'sender_path': 'common.djangoapps.student.models.CourseEnrollment', + }, ], }, }, @@ -69,6 +75,7 @@ def ready(self): # pylint: disable=unused-import, import-error, import-outside-toplevel # This is required in order to register the receiver inside handlers module. from cms.djangoapps.contentstore.signals import handlers # noqa: F401 + run_init_pipeline() diff --git a/eox_nelp/init_pipeline.py b/eox_nelp/init_pipeline.py index d351d648..a7b46259 100644 --- a/eox_nelp/init_pipeline.py +++ b/eox_nelp/init_pipeline.py @@ -42,14 +42,16 @@ def set_mako_templates(): # and therefore the settings has not been set yet from eox_nelp.course_experience.frontend import templates as course_experience_templates from eox_nelp.edxapp_wrapper.edxmako import edxmako + from eox_nelp.payment_notifications import templates as payment_notifications_templates from eox_nelp.stats import templates as stats_templates - templates_modules_to_include = [ + module_templates_to_include = [ stats_templates, course_experience_templates, + payment_notifications_templates, ] - for module in templates_modules_to_include: + for module in module_templates_to_include: path_to_templates = os.path.dirname(module.__file__) if path_to_templates not in edxmako.LOOKUP['main'].directories: diff --git a/eox_nelp/migrations/0005_paymentnotification.py b/eox_nelp/migrations/0005_paymentnotification.py new file mode 100644 index 00000000..846ff684 --- /dev/null +++ b/eox_nelp/migrations/0005_paymentnotification.py @@ -0,0 +1,56 @@ +# Generated by Django 3.2.13 on 2023-07-26 15:21 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('eox_nelp', '0004_feedback_public_default_to_false'), + ] + + operations = [ + migrations.CreateModel( + name='PaymentNotification', + fields=[ + ('id', models.AutoField(primary_key=True, serialize=False)), + ('cdtrans_lms_user_id', models.IntegerField(blank=True, db_index=True, null=True)), + ('cdtrans_sku', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_username', models.CharField(blank=True, max_length=200, null=True)), + ('cdtrans_email', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_amount', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_course_id', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_enrollment_id', models.IntegerField(blank=True, null=True)), + ('cdtrans_mode', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_cert_status', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_date', models.DateTimeField(blank=True, null=True)), + ('cdtrans_response_id', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_status', models.CharField(blank=True, max_length=100, null=True)), + ('cdtrans_ecom_order_id', models.IntegerField(blank=True, null=True)), + ('cdtrans_ecom_payment_reponse_id', models.IntegerField(blank=True, null=True)), + ('cdtrans_extra_data_1', models.CharField(blank=True, max_length=1000, null=True)), + ('cdtrans_extra_data_2', models.CharField(blank=True, max_length=1000, null=True)), + ('cdtrans_extra_data_3', models.CharField(blank=True, max_length=1000, null=True)), + ('cdtrans_extra_data_4', models.TextField(blank=True, null=True)), + ('show_msg_case0', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('show_msg_case1', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('show_msg_case2', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('show_trans_info', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('show_msg_custom', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('custom_msg', models.TextField(blank=True, help_text='Not ready', null=True)), + ('call_to_action_1_msg', models.CharField(blank=True, help_text='Not ready', max_length=1000, null=True)), + ('call_to_action_2_msg', models.CharField(blank=True, help_text='Not ready', max_length=1000, null=True)), + ('call_to_action_3_msg', models.CharField(blank=True, help_text='Not ready', max_length=1000, null=True)), + ('call_to_action_1_url', models.CharField(blank=True, help_text='Not ready', max_length=1000, null=True)), + ('call_to_action_2_url', models.CharField(blank=True, help_text='Not ready', max_length=1000, null=True)), + ('call_to_action_3_url', models.CharField(blank=True, help_text='Not ready', max_length=1000, null=True)), + ('redirect_from_dashboard', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('redirect_from_course', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('redirect_from_certificate', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('redirect_from_everywhere', models.BooleanField(blank=True, help_text='Not ready', null=True)), + ('internal_status', models.CharField(choices=[('case_0', 'case_0'), ('case_1', 'case_1'), ('case_2', 'case_2'), ('pending_manual_eval', 'pending_manual_eval'), ('other_case', 'other_case'), ('ignore', 'ignore'), ('resolution_by_case_0', 'resolution_by_case_0'), ('resolution_by_case_1', 'resolution_by_case_1'), ('resolution_by_case_2', 'resolution_by_case_2'), ('resolution_other', 'resolution_other')], default='case_0', max_length=30)), + ('internal_notes', models.CharField(blank=True, max_length=2000, null=True)), + ('internal_view_count', models.IntegerField(default=0)), + ], + ), + ] diff --git a/eox_nelp/migrations/0006_auto_20230726_1707.py b/eox_nelp/migrations/0006_auto_20230726_1707.py new file mode 100644 index 00000000..5ac9f937 --- /dev/null +++ b/eox_nelp/migrations/0006_auto_20230726_1707.py @@ -0,0 +1,23 @@ +# Generated by Django 3.2.13 on 2023-07-26 17:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ('eox_nelp', '0005_paymentnotification'), + ] + + operations = [ + migrations.AddField( + model_name='paymentnotification', + name='cdtrans_card_last_4_digits', + field=models.CharField(blank=True, max_length=10, null=True), + ), + migrations.AlterField( + model_name='paymentnotification', + name='internal_notes', + field=models.TextField(blank=True, max_length=2000, null=True), + ), + ] diff --git a/eox_nelp/payment_notifications/__init__.py b/eox_nelp/payment_notifications/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eox_nelp/payment_notifications/admin.py b/eox_nelp/payment_notifications/admin.py new file mode 100644 index 00000000..edc6735e --- /dev/null +++ b/eox_nelp/payment_notifications/admin.py @@ -0,0 +1,108 @@ +""" +Payment notifications admin file. + +This module contains the admin configuration for the PaymentNotification model. +It defines the admin class PaymentNotificationAdmin, which specifies how the +PaymentNotification model is displayed and interacted with in the Django admin interface. + +Attributes: + PaymentNotificationAdmin (admin.ModelAdmin): The admin class for PaymentNotification + that customizes the display and functionality of the admin interface for this model. + +This admin class defines the list of fields to be displayed, search fields, and filters +for PaymentNotification objects. It also includes several methods for summarizing +user data, transaction data, and message cases, which are used for displaying information +in the admin interface. + +Methods: + - user_summary(self, obj): Summarizes user data. + - transaction_summary(self, obj): Summarizes transaction data. + - msg_cases(self, obj): Shows message case state. + - redirections_state(self, obj): Shows redirections state. +""" +from django.contrib import admin + +from eox_nelp.payment_notifications.models import PaymentNotification + + +class PaymentNotificationAdmin(admin.ModelAdmin): + """Admin class for PaymentNotification.""" + + list_display = ( + "user_summary", + "internal_status", + "cdtrans_amount", + "cdtrans_date", + "transaction_summary", + "msg_cases", + "redirections_state", + "internal_view_count", + ) + search_fields = ( + "cdtrans_lms_user_id", + "cdtrans_username", + "cdtrans_email", + "cdtrans_course_id", + "cdtrans_response_id", + "cdtrans_amount", + "cdtrans_course_id", + "internal_status", + "cdtrans_cert_status", + "cdtrans_enrollment_id", + "cdtrans_sku", + ) + list_filter = ( + "cdtrans_course_id", + "cdtrans_amount", + "internal_status", + "show_msg_case0", + "show_msg_case1", + "show_msg_case2", + "show_msg_custom", + "redirect_from_dashboard", + "redirect_from_course", + "redirect_from_certificate", + "redirect_from_everywhere", + ) + + def user_summary(self, obj): + """Summaries user data""" + return f""" + lms_user_id: {obj.cdtrans_lms_user_id} + username: {obj.cdtrans_username} + email: {obj.cdtrans_email} + course_id: {obj.cdtrans_course_id} + enrollment_id: {obj.cdtrans_enrollment_id} + certificate_status: {obj.cdtrans_cert_status} + """ + + def transaction_summary(self, obj): + """Summaries transaction data""" + return f""" + sku: {obj.cdtrans_sku} + response_id: {obj.cdtrans_response_id} + status: {obj.cdtrans_status} + response_ id: {obj.cdtrans_response_id} + amount: {obj.cdtrans_amount} + date: {obj.cdtrans_date} + """ + + def msg_cases(self, obj): + """Show msg case state""" + return f""" + show_msg_case0: {obj.show_msg_case0} + show_msg_case1: {obj.show_msg_case1} + show_msg_case2: {obj.show_msg_case2} + """ + + def redirections_state(self, obj): + """Show redirections state""" + return f""" + redirect_from_dashboard: {obj.redirect_from_dashboard} + redirect_from_course: {obj.redirect_from_course} + redirect_from_certificate: {obj.redirect_from_certificate} + redirect_from_everywhere : {obj.redirect_from_everywhere} + """ + + +admin.site.register(PaymentNotification, PaymentNotificationAdmin) diff --git a/eox_nelp/payment_notifications/context_processor.py b/eox_nelp/payment_notifications/context_processor.py new file mode 100644 index 00000000..2557bec1 --- /dev/null +++ b/eox_nelp/payment_notifications/context_processor.py @@ -0,0 +1,20 @@ +""" +Get the payment notifications context. + +This function is used to obtain the necessary context for payment notifications +and returns it as a dictionary. + +Args: + request: The HttpRequest object representing the HTTP request. + +Returns: + dict: A dictionary with the payment notifications context. +""" +from eox_nelp.payment_notifications.views import get_payment_notifications_context + + +def payments_notifications_context(request): + """ + This function works as a payment notification context + """ + return get_payment_notifications_context(request) diff --git a/eox_nelp/payment_notifications/models.py b/eox_nelp/payment_notifications/models.py new file mode 100644 index 00000000..47180975 --- /dev/null +++ b/eox_nelp/payment_notifications/models.py @@ -0,0 +1,121 @@ +""" +eox_nelp model for notifications +""" +import logging + +from django.db import models + +logger = logging.getLogger(__name__) + + +class PaymentNotification(models.Model): + """ + PaymentNotification model + """ + id = models.AutoField(primary_key=True) + + # This data comes from the Payment transaction + cdtrans_lms_user_id = models.IntegerField(db_index=True, null=True, blank=True) + + cdtrans_sku = models.CharField(max_length=100, null=True, blank=True) + cdtrans_username = models.CharField(max_length=200, null=True, blank=True) + cdtrans_email = models.CharField(max_length=100, null=True, blank=True) + cdtrans_amount = models.CharField(max_length=100, null=True, blank=True) + cdtrans_course_id = models.CharField(max_length=100, null=True, blank=True) + cdtrans_enrollment_id = models.IntegerField(null=True, blank=True) + cdtrans_mode = models.CharField(max_length=100, null=True, blank=True) + cdtrans_cert_status = models.CharField(max_length=100, null=True, blank=True) + cdtrans_date = models.DateTimeField(null=True, blank=True) + cdtrans_response_id = models.CharField(max_length=100, null=True, blank=True) + cdtrans_status = models.CharField(max_length=100, null=True, blank=True) + cdtrans_ecom_order_id = models.IntegerField(null=True, blank=True) + cdtrans_ecom_payment_reponse_id = models.IntegerField(null=True, blank=True) + + cdtrans_card_last_4_digits = models.CharField(max_length=10, null=True, blank=True) + + cdtrans_extra_data_1 = models.CharField(max_length=1000, null=True, blank=True) + cdtrans_extra_data_2 = models.CharField(max_length=1000, null=True, blank=True) + cdtrans_extra_data_3 = models.CharField(max_length=1000, null=True, blank=True) + cdtrans_extra_data_4 = models.TextField(null=True, blank=True) + + # Control surface + show_msg_case0 = models.BooleanField(null=True, blank=True, help_text="Will show the case 0 msg to the user") + show_msg_case1 = models.BooleanField(null=True, blank=True, help_text="Will show the case 1 msg to the user") + show_msg_case2 = models.BooleanField(null=True, blank=True, help_text="Will show the case 2 msg to the user") + + show_trans_info = models.BooleanField( + null=True, + blank=True, + help_text="Will show the transaction details to the user", + ) + + show_msg_custom = models.BooleanField(null=True, blank=True, help_text="Will show the following html to the user") + custom_msg = models.TextField( + null=True, + blank=True, + help_text='Use a "lang-ar" or "lang-en" class to select language', + ) + + call_to_action_1_msg = models.CharField( + max_length=1000, + null=True, + blank=True, + help_text="Name of the button for case 1", + ) + call_to_action_2_msg = models.CharField( + max_length=1000, + null=True, blank=True, + help_text="Name of the button for case 2", + ) + call_to_action_3_msg = models.CharField( + max_length=1000, + null=True, + blank=True, + help_text="Name of the button at the end of the message", + ) + + call_to_action_1_url = models.CharField( + max_length=1000, + null=True, + blank=True, + help_text="Link of the button for case 1", + ) + call_to_action_2_url = models.CharField( + max_length=1000, + null=True, + blank=True, + help_text="Link of the button for case 2", + ) + call_to_action_3_url = models.CharField( + max_length=1000, + null=True, + blank=True, + help_text="Link of the button at the end of the message", + ) + + redirect_from_dashboard = models.BooleanField(null=True, blank=True, help_text="Not ready") + redirect_from_course = models.BooleanField(null=True, blank=True, help_text="Not ready") + redirect_from_certificate = models.BooleanField(null=True, blank=True, help_text="Not ready") + redirect_from_everywhere = models.BooleanField(null=True, blank=True, help_text="Not ready") + + # Dashboard control + INTERNAL_STATUS = [ + ("case_0", "case_0"), + ("case_1", "case_1"), + ("case_2", "case_2"), + ("pending_manual_eval", "pending_manual_eval"), + ("other_case", "other_case"), + ("ignore", "ignore"), + ("resolution_by_case_0", "resolution_by_case_0"), + ("resolution_by_case_1", "resolution_by_case_1"), + ("resolution_by_case_2", "resolution_by_case_2"), + ("resolution_other", "resolution_other"), + ] + internal_status = models.CharField( + max_length=30, + choices=INTERNAL_STATUS, + default='case_0', + ) + internal_notes = models.TextField(max_length=2000, null=True, blank=True) + + internal_view_count = models.IntegerField(default=0) diff --git a/eox_nelp/payment_notifications/templates/__init__.py b/eox_nelp/payment_notifications/templates/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/eox_nelp/payment_notifications/templates/payment_notifications.html b/eox_nelp/payment_notifications/templates/payment_notifications.html new file mode 100644 index 00000000..f4805bd6 --- /dev/null +++ b/eox_nelp/payment_notifications/templates/payment_notifications.html @@ -0,0 +1,210 @@ +<%namespace name='static' file='/static_content.html'/> +<%! +from django.conf import settings +from django.urls import reverse +from django.utils.translation import ugettext as _ +from django.contrib.auth import get_user_model +from lms.djangoapps.grades.api import CourseGradeFactory +from opaque_keys.edx.keys import CourseKey + +from eox_nelp.edxapp_wrapper.course_overviews import CourseOverview + +payment_links = getattr(settings, "PAYMENT_LINKS_BY_COURSE", {}) +User = get_user_model() +%> + +% if len(payment_notifications) > 0: + + + + +
لديك الإخطارات التالية
+You have the following notifications
+ % endif + +