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: + + + + +
+
+
+ + % if payment_notifications: +

لديك الإخطارات التالية

+

You have the following notifications

+ % endif + +
+ % for payment_notification in payment_notifications: + + <% + passed = False + + try: + payment_link = payment_links.get(payment_notification.cdtrans_course_id, "link-not-set") + user = User.objects.get(id=payment_notification.cdtrans_lms_user_id) + course_key = CourseKey.from_string(payment_notification.cdtrans_course_id) + grade = CourseGradeFactory().read(user, course_key=course_key) + course_overview = CourseOverview.objects.get(id=course_key) + course_name = course_overview.display_name + passed = grade and grade.passed + course_about_link = reverse('about_course', args=[payment_notification.cdtrans_course_id]) + except: + pass + %> + + % if payment_notification.show_msg_case0 and passed and payment_notification.internal_status == "case_0": +
+ لقد أتممت دورة ${course_name} بنجاح وشهادتك تحت المراجعة. ستصلك رسالة على بريدك الإلكتروني عند إصدارها. +
+
+ You have passed the ${course_name} course and your certificate is being reviewed. You will receive an email message when the certificate is issued. +
+ % endif + + + % if payment_notification.show_msg_case1 and payment_notification.internal_status == "case_1": +
+ + + +
+ يؤسفنا إبلاغك بأن عملية الدفع لم تتم ولم يتم خصم رسوم دورة ${course_name}، للإستمرار في الدورة والحصول على الشهادة يمكنك إكمال عملية الدفع من خلال الرابط التالي + + %if payment_notification.call_to_action_1_url: + ${ payment_notification.call_to_action_1_msg } + %endif +
+ + +
+ +
+ + + +
+ We regret to inform you that the payment process was not completed and the ${course_name} course fees were not deducted. On the certificate you can complete the payment process through the following link. + + %if payment_notification.call_to_action_1_url: + ${ payment_notification.call_to_action_1_msg } + %endif +
+ + +
+ % endif + + + % if payment_notification.show_msg_case2: +
+ Message Case 2 + لكن لا بد أن أوضح لك أن كل هذه الأفكار المغلوطة حول استنكار النشوة وتمجيد الألم نشأت بالفعل، وسأعرض لك التفاصيل لتكتشف حقيقة وأساس تلك السعادة البشرية، فلا أحد يرفض أو يكره أو يتجنب الشعور بالسعادة، ولكن بفضل هؤلاء الأشخاص الذين لا يدركون بأن السعادة لا بد أن نستشعرها بصورة أكثر عقلانية ومنطقية فيعرضهم هذا لمواجهة الظروف الأليمة، وأكرر بأنه لا يوجد من يرغب في الحب ونيل المنال ويتلذذ بالآلام، الألم هو الألم ولكن نتيجة لظروف ما قد تكمن السعاده فيما نتحمله من كد وأسي. +
+
+ Message Case 2 + Nunc scelerisque viverra mauris in aliquam sem fringilla. Amet aliquam id diam maecenas ultricies mi eget. Lorem mollis aliquam ut porttitor leo a diam. Integer quis auctor elit sed vulputate mi sit amet. Pellentesque diam volutpat commodo sed. Amet massa vitae tortor condimentum. Tempus imperdiet nulla malesuada pellentesque elit. Pharetra vel turpis nunc eget lorem dolor sed. Pretium quam vulputate dignissim suspendisse in. Mus mauris vitae ultricies leo integer. +
+ + %if payment_notification.call_to_action_2_url: + + %endif + % endif + + % if payment_notification.custom_msg: + ${ payment_notification.custom_msg } + % endif + + % endfor + + % for payment_notification in payment_notifications: + % if payment_notification.show_trans_info: +
+

بيانات المعاملات:

+
    +
  • تاريخ: ${payment_notification.cdtrans_date}
  • +
  • كمية: ${payment_notification.cdtrans_amount}
  • +
  • دورة: ${payment_notification.cdtrans_course_id}
  • +
  • رقم المعاملة: ${payment_notification.cdtrans_response_id}
  • +
+
+
+

Transaction info:

+
    +
  • Date: ${payment_notification.cdtrans_date}
  • +
  • Amount: ${payment_notification.cdtrans_amount}
  • +
  • Course: ${payment_notification.cdtrans_course_id}
  • +
  • ID: ${payment_notification.cdtrans_response_id}
  • +
+
+ % endif + % endfor + + % for payment_notification in payment_notifications: + %if payment_notification.call_to_action_3_url: + + %endif + %endfor + +
+
+
+ +% endif diff --git a/eox_nelp/payment_notifications/templates/payment_notifications_with_frame.html b/eox_nelp/payment_notifications/templates/payment_notifications_with_frame.html new file mode 100644 index 00000000..b77b1215 --- /dev/null +++ b/eox_nelp/payment_notifications/templates/payment_notifications_with_frame.html @@ -0,0 +1,8 @@ +<%page expression_filter="h"/> +<%! from django.utils.translation import ugettext as _ %> +<%namespace name='static' file='/static_content.html'/> +<%inherit file="/main.html" /> + +<%block name="pagetitle">${_("Payment notifications")} + +<%include file="/payment_notifications.html"/> diff --git a/eox_nelp/payment_notifications/urls.py b/eox_nelp/payment_notifications/urls.py new file mode 100644 index 00000000..caaa752e --- /dev/null +++ b/eox_nelp/payment_notifications/urls.py @@ -0,0 +1,12 @@ +""" +eox_nelp notifications for payment status +""" +from django.urls import path + +from eox_nelp.payment_notifications.views import PaymentNotificationsView + +app_name = 'eox_nelp' # pylint: disable=invalid-name + +urlpatterns = [ # pylint: disable=invalid-name + path("", PaymentNotificationsView.as_view(), name="payment-notifications"), +] diff --git a/eox_nelp/payment_notifications/views.py b/eox_nelp/payment_notifications/views.py new file mode 100644 index 00000000..ff20824b --- /dev/null +++ b/eox_nelp/payment_notifications/views.py @@ -0,0 +1,86 @@ +""" +Payment Notifications views +""" +from django.conf import settings +from django.contrib.auth.decorators import login_required +from django.http import Http404 +from django.utils.decorators import method_decorator +from django.views import View + +from eox_nelp.edxapp_wrapper.edxmako import edxmako +from eox_nelp.payment_notifications.models import PaymentNotification + + +@method_decorator(login_required, name='dispatch') +class PaymentNotificationsView(View): + """ + Display a PaymentNotification for users that navigate to /payment-notifications + """ + + def get(self, request, *args, **kwargs): # pylint: disable=unused-argument + """ + Checks whether payment notifications are enabled in the system configuration + before displaying the payment notifications page. If payment notifications + are not enabled, it raises an Http404 response. + + Args: + request (HttpRequest): The incoming HTTP request. + *args: Additional positional arguments. + **kwargs: Additional keyword arguments. + + Returns: + HttpResponse: An HTTP response that renders the "payment_notifications_with_frame.html" + template within the current context. + + Raises: + Http404: If payment notifications are not enabled in the configuration. + """ + + if not getattr(settings, "ENABLE_PAYMENT_NOTIFICATIONS", None): + raise Http404 + + return edxmako.shortcuts.render_to_response("payment_notifications_with_frame.html", {}, "main", request) + + +def get_payment_notifications_context(request): + """ + Calculate the notifications for a user. + """ + default_context = { + "payment_notifications": [], + } + + if not getattr(settings, "ENABLE_PAYMENT_NOTIFICATIONS", None): + return default_context + + user_id = request.user.id + + # count the views that belong to real users looking at their dashboard or notifications view + count_view = False + count_in_paths = [ + '/dashboard', + '/eox-nelp/payment-notifications', + ] + if any(x in request.path for x in count_in_paths): + count_view = True + else: + # if the view is not part in the list we dont really need to do any query + return default_context + + # allows staff users to masquerade to debug issues + if request.GET.get("showpaymentnotificationsforuser", False) and request.user.is_staff: + user_id = request.GET.get("showpaymentnotificationsforuser", user_id) + count_view = False + + all_notifications_for_user = PaymentNotification.objects.filter( # pylint: disable=no-member + cdtrans_lms_user_id=user_id + ) + if count_view: + for notification in all_notifications_for_user: + notification.internal_view_count += 1 + notification.save() + + context = { + "payment_notifications": all_notifications_for_user, + } + return context diff --git a/eox_nelp/settings/common.py b/eox_nelp/settings/common.py index 2e92b171..11475b10 100644 --- a/eox_nelp/settings/common.py +++ b/eox_nelp/settings/common.py @@ -59,3 +59,18 @@ def plugin_settings(settings): settings.INSTALLED_APPS.append(JSON_API_REST_FRAMEWORK) if find_spec('eox_audit_model') and EOX_AUDIT_MODEL_APP not in settings.INSTALLED_APPS: settings.INSTALLED_APPS.append(EOX_AUDIT_MODEL_APP) + + try: + payments_notifications_context = ( + 'eox_nelp.payment_notifications.context_processor.payments_notifications_context' + ) + + if payments_notifications_context not in settings.TEMPLATES[0]['OPTIONS']['context_processors']: + settings.TEMPLATES[0]['OPTIONS']['context_processors'].append(payments_notifications_context) + if payments_notifications_context not in settings.TEMPLATES[1]['OPTIONS']['context_processors']: + settings.TEMPLATES[1]['OPTIONS']['context_processors'].append(payments_notifications_context) + + settings.DEFAULT_TEMPLATE_ENGINE = settings.TEMPLATES[0] + except AttributeError: + # We must find a way to register this error + pass diff --git a/eox_nelp/signals/receivers.py b/eox_nelp/signals/receivers.py index 13209326..1862cc08 100644 --- a/eox_nelp/signals/receivers.py +++ b/eox_nelp/signals/receivers.py @@ -15,6 +15,7 @@ from openedx_events.learning.data import CertificateData, CourseData, UserData, UserPersonalData from eox_nelp.notifications.tasks import create_course_notifications as create_course_notifications_task +from eox_nelp.payment_notifications.models import PaymentNotification from eox_nelp.signals.tasks import create_external_certificate, dispatch_futurex_progress from eox_nelp.signals.utils import _generate_external_certificate_data @@ -185,3 +186,31 @@ def enrollment_publisher(instance, **kwargs): # pylint: disable=unused-argument instance.user.username, instance.course_id, ) + + +def update_payment_notifications(instance, **kwargs): # pylint: disable=unused-argument + """This update the internal status of a payment notification record, + if the enrollment is active an have the no-id-professional mode this will set + the internal status as resolution_by_case_1 + """ + if not instance.is_active or instance.mode != "no-id-professional": + return + + user = instance.user + course_key = instance.course_id + + payment_notifications = PaymentNotification.objects.filter( # pylint: disable=no-member + cdtrans_lms_user_id=user.id, + cdtrans_course_id=str(course_key), + internal_status="case_1", + ) + + for payment_notification in payment_notifications: + payment_notification.internal_status = "resolution_by_case_1" + payment_notification.save() + + LOGGER.info( + "The internal status of the payment notification with id %s has been updated to %s", + payment_notification.id, + payment_notification.internal_status, + ) diff --git a/eox_nelp/urls.py b/eox_nelp/urls.py index 2d70d7c9..d2a665b8 100644 --- a/eox_nelp/urls.py +++ b/eox_nelp/urls.py @@ -30,4 +30,5 @@ ), path('api/stats/', include('eox_nelp.stats.api.urls', namespace='stats-api')), path('stats/', include('eox_nelp.stats.urls', namespace='stats')), + path('payment-notifications/', include('eox_nelp.payment_notifications.urls', namespace='payment-notifications')), ]