overhangio / tutor-discovery

Course Discovery plugin for Tutor
GNU Affero General Public License v3.0
12 stars 41 forks source link

Issue finishing a program whose all courses are finished #59

Closed Silidrone closed 8 months ago

Silidrone commented 9 months ago

I've set up a single program to demonstrate this issue. I have a single course inside that program. My program type is honor. I have earned an Honor certificate for the single course inside my program, and I was expecting to complete the program. However, I only see image

So as you can see, the certificate for the course is showing, but completion of this course does not count toward the completion of the program. I've went inside the code and figured out that after I cache the programs, the cached program's course's course run's type is always None. I do not understand why. So inside openedx/core/djangoapps/catalog/utils.py on line 121: program = cache.get(PROGRAM_CACHE_KEY_TPL.format(uuid=uuid))

program is:

{
    'program-3883fdfa-a658-4a7c-a17a-fedb9d90dc07': {
        'uuid': '3883fdfa-a658-4a7c-a17a-fedb9d90dc07',
        'title': 'program1',
        'subtitle': '',
        'type': 'Honor',
        'type_attrs': {
            'uuid': '3f687c41-4319-4bb2-b5de-a03c22df7e49',
            'slug': 'honor',
            'coaching_supported': False
        },
        'status': 'active',
        'marketing_slug': 'program1',
        'marketing_url': 'honor/program1',
        'banner_image': {
            'large': {
                'url': 'http://discovery.local.overhang.io/media/media/programs/banner_images/3883fdfa-a658-4a7c-a17a-fedb9d90dc07-afa46d0d3bed.large.png',
                'width': 1440,
                'height': 480
            },
            'medium': {
                'url': 'http://discovery.local.overhang.io/media/media/programs/banner_images/3883fdfa-a658-4a7c-a17a-fedb9d90dc07-afa46d0d3bed.medium.png',
                'width': 726,
                'height': 242
            },
            'small': {
                'url': 'http://discovery.local.overhang.io/media/media/programs/banner_images/3883fdfa-a658-4a7c-a17a-fedb9d90dc07-afa46d0d3bed.small.png',
                'width': 435,
                'height': 145
            },
            'x-small': {
                'url': 'http://discovery.local.overhang.io/media/media/programs/banner_images/3883fdfa-a658-4a7c-a17a-fedb9d90dc07-afa46d0d3bed.x-small.png',
                'width': 348,
                'height': 116
            }
        },
        'hidden': False,
        'courses': [{
            'key': 'TestOrg+QP101',
            'uuid': '243897b4-356c-43c0-be72-9cc4c991f4c0',
            'title': 'Intro to quantum physics',
            'course_runs': [{
                'key': 'course-v1:TestOrg+QP101+2023_T2',
                'uuid': '41151902-5874-46bc-a71f-334fa2645403',
                'title': 'Intro to quantum physics',
                'external_key': None,
                'image': {
                    'src': 'http://local.overhang.io/asset-v1:TestOrg+QP101+2023_T2+type@asset+block@images_course_image.jpg',
                    'description': None,
                    'height': None,
                    'width': None
                },
                'short_description': None,
                'marketing_url': None,
                'seats': [],
                'start': '2023-01-01T00:00:00Z',
                'end': '2024-03-09T00:00:00Z',
                'go_live_date': None,
                'enrollment_start': None,
                'enrollment_end': None,
                'weeks_to_complete': None,
                'pacing_type': 'self_paced',
                'type': None,
                'run_type': '9dc9f0ca-3467-4cf7-aac6-fad8167a3c74',
                'status': 'published',
                'is_enrollable': True,
                'is_marketable': False,
                'availability': 'Current'
            }],
            'entitlements': [],
            'owners': [],
            'image': {
                'src': 'http://local.overhang.io/asset-v1:TestOrg+QP101+2023_T2+type@asset+block@images_course_image.jpg',
                'description': None,
                'height': None,
                'width': None
            },
            'short_description': None,
            'type': '9b5fe3b2-50e4-45bf-9dd5-0b290d61e8b4',
            'url_slug': None,
            'course_type': 'empty',
            'enterprise_subscription_inclusion': True,
            'excluded_from_seo': False,
            'excluded_from_search': False
        }],
        'authoring_organizations': [],
        'card_image_url': None,
        'is_program_eligible_for_one_click_purchase': False,
        'degree': None,
        'curricula': [],
        'marketing_hook': '',
        'total_hours_of_effort': None,
        'recent_enrollment_count': 0,
        'organization_short_code_override': '',
        'organization_logo_override_url': None,
        'primary_subject_override': None,
        'level_type_override': None,
        'language_override': None,
        'labels': [],
        'taxi_form': None,
        'program_duration_override': None,
        'data_modified_timestamp': '2023-12-28T08:51:21.520090Z',
        'excluded_from_search': False,
        'excluded_from_seo': False,
        'overview': '',
        'weeks_to_complete': None,
        'weeks_to_complete_min': None,
        'weeks_to_complete_max': None,
        'min_hours_effort_per_week': None,
        'max_hours_effort_per_week': None,
        'video': None,
        'expected_learning_items': [],
        'faq': [],
        'credit_backing_organizations': [],
        'corporate_endorsements': [],
        'job_outlook_items': [],
        'individual_endorsements': [],
        'languages': [],
        'transcript_languages': [],
        'subjects': [],
        'price_ranges': [],
        'staff': [],
        'credit_redemption_overview': '',
        'applicable_seat_types': ['audit', 'credit', 'professional', 'verified', 'honor'],
        'instructor_ordering': [],
        'enrollment_count': 0,
        'topics': [],
        'credit_value': 0,
        'enterprise_subscription_inclusion': False,
        'geolocation': None,
        'location_restriction': None,
        'is_2u_degree_program': False,
        'in_year_value': None,
        'skill_names': [],
        'skills': [],
        'product_source': {
            'name': 'sourcd1',
            'slug': 'sourcd1',
            'description': ''
        },
        'subscription_eligible': None,
        'subscription_prices': [],
        'pathway_ids': []
    }
}

I've looked at the discovery database and found something that didn't look right: all of the type_id's inside course_metadata_course_run table are set to 5, which is a course_type EMPTY, even though I selected honor. But even after manually changing this and re-caching, my problem wasn't solved. I also tried running refresh metadata but the issue persists.

Also, I managed to hard-code a solution only for understanding the underlying issue, maybe this will be helpful as well:

When I put the following code inside openedx/core/djangoapps/programs/utils.py on line 467

for course_run in course['course_runs']:
    course_run['type'] = CourseMode.HONOR

I get: image

What could be the issue? Why is the course_run's type always None? How can I finish a program by finishing the courses inside it?|

I am using tutor to run openedx. My discovery plugin version is: 16.0.0 My tutor version is: 16.1.7

Faraz32123 commented 8 months ago

Hi @Silidrone , As far as I understand, your course default mode is not set to 'Honor'. Can u try below settings in a patch named openedx-common-settings through a plugin and let me know if it works. I'll look further into the issue to find a proper solution until then.

COURSE_MODE_DEFAULTS['name'] = "Honor"
COURSE_MODE_DEFAULTS['slug'] = "honor"
Silidrone commented 8 months ago

I created a plugin like this:

from tutor import hooks

hooks.Filters.ENV_PATCHES.add_items([
    (
        "openedx-common-settings",
        "COURSE_MODE_DEFAULTS['name'] = 'Honor'"
    ),
    (
        "openedx-common-settings",
        "COURSE_MODE_DEFAULTS['slug'] = 'honor'"
    ),
])

I enabled it, ran tutor local launch and verified it is enabled, and it didnt solve the issue. I found out what was the issue though. Apparently, the type_id (this type_id btw, when copied using refresh_metadata always sets the type to EMPTY) of the course_metadata_courserun is not even important, as the type_legacy @property is taken from the CourseRun model, which only uses the associated seat. Now, I didnt have any seat. When I added a seat of type honor for the corresponding course run, everything works. But what if I don't want to have seats? Do I have to add a seat for each course run that I will use to complete in my programs?

Faraz32123 commented 8 months ago

Hi @Silidrone, Yes you are right, seats are required to complete the courses/programs and seats are created in ecommerce for the courses in programs. You have to use ecommerce service for this.

regisb commented 8 months ago

It looks like this is not an issue with tutor-ecommerce, right? If so, please close this issue.