def publish_to_ecommerce(self, partner, course_run): api = EdxRestApiClient(partner.ecommerce_api_url, jwt=partner.access_token) data = { 'id': course_run.lms_course_id, 'name': course_run.title_override or course_run.course.title, 'verification_deadline': serialize_datetime(course_run.end), 'create_or_activate_enrollment_code': False, # NOTE (CCB): We only order here to aid testing. The E-Commerce API does NOT care about ordering. 'products': [ serialize_seat_for_ecommerce_api(seat) for seat in course_run.seats.exclude( type=Seat.CREDIT).order_by('created') ], } try: api.publication.post(data) return self.PUBLICATION_SUCCESS_STATUS except SlumberBaseException as ex: content = ex.content.decode('utf8') logger.exception( 'Failed to publish course run [%d] to E-Commerce! Error was: [%s]', course_run.pk, content) return 'FAILED: ' + content
def publish_to_ecommerce(self, partner, course_run): course_key = self.get_course_key(course_run.course) discovery_course = Course.objects.get(partner=partner, key=course_key) api = EdxRestApiClient(partner.ecommerce_api_url, jwt=partner.access_token) data = { 'id': course_run.lms_course_id, 'uuid': str(discovery_course.uuid), 'name': course_run.title_override or course_run.course.title, 'verification_deadline': serialize_datetime(course_run.end), } # NOTE: We only order here to aid testing. The E-Commerce API does NOT care about ordering. products = [ serialize_seat_for_ecommerce_api(seat) for seat in course_run.seats.exclude( type=Seat.CREDIT).order_by('created') ] products.extend([ serialize_entitlement_for_ecommerce_api(entitlement) for entitlement in course_run.course.entitlements.order_by('created') ]) data['products'] = products try: api.publication.post(data) return self.PUBLICATION_SUCCESS_STATUS except SlumberBaseException as ex: content = ex.content.decode('utf8') logger.exception( 'Failed to publish course run [%d] to E-Commerce! Error was: [%s]', course_run.pk, content) return 'FAILED: ' + content
def test_serialize_seat_for_ecommerce_api_with_id_verification( self, seat_type): seat = SeatFactory(type=seat_type) actual = serialize_seat_for_ecommerce_api(seat) expected_attribute_values = [{ 'name': 'certificate_type', 'value': seat_type, }, { 'name': 'id_verification_required', 'value': True, }] assert actual['attribute_values'] == expected_attribute_values
def test_serialize_seat_for_ecommerce_api_with_audit_seat(self): seat = SeatFactory(type=Seat.AUDIT) actual = serialize_seat_for_ecommerce_api(seat) expected = { 'expires': serialize_datetime(seat.calculated_upgrade_deadline), 'price': str(seat.price), 'product_class': 'Seat', 'attribute_values': [{ 'name': 'certificate_type', 'value': '', }, { 'name': 'id_verification_required', 'value': False, }] } assert actual == expected
def test_serialize_seat_for_ecommerce_api(self): seat = SeatFactory() actual = serialize_seat_for_ecommerce_api(seat) assert actual['price'] == str(seat.price) assert actual['product_class'] == 'Seat'
def test_publish(self, mock_access_token): # pylint: disable=unused-argument,too-many-statements publisher_course_run = self._create_course_run_for_publication() currency = Currency.objects.get(code='USD') common_seat_kwargs = { 'course_run': publisher_course_run, 'currency': currency, } audit_seat = SeatFactory(type=Seat.AUDIT, upgrade_deadline=None, **common_seat_kwargs) # The credit seat should NOT be published. SeatFactory(type=Seat.CREDIT, **common_seat_kwargs) professional_seat = SeatFactory(type=Seat.PROFESSIONAL, **common_seat_kwargs) verified_seat = SeatFactory(type=Seat.VERIFIED, **common_seat_kwargs) partner = publisher_course_run.course.organizations.first().partner self._set_test_client_domain_and_login(partner) self._mock_studio_api_success(publisher_course_run) self._mock_ecommerce_api(publisher_course_run) url = reverse('publisher:api:v1:course_run-publish', kwargs={'pk': publisher_course_run.pk}) response = self.client.post(url, {}) assert response.status_code == 200 assert len(responses.calls) == 3 expected = { 'discovery': CourseRunViewSet.PUBLICATION_SUCCESS_STATUS, 'ecommerce': CourseRunViewSet.PUBLICATION_SUCCESS_STATUS, 'studio': CourseRunViewSet.PUBLICATION_SUCCESS_STATUS, } assert response.data == expected # Verify the correct deadlines were sent to the E-Commerce API ecommerce_body = json.loads(responses.calls[2].request.body) expected = [ serialize_seat_for_ecommerce_api(audit_seat), serialize_seat_for_ecommerce_api(professional_seat), serialize_seat_for_ecommerce_api(verified_seat), ] assert ecommerce_body['products'] == expected assert ecommerce_body['verification_deadline'] == serialize_datetime( publisher_course_run.end) discovery_course_run = CourseRun.objects.get( key=publisher_course_run.lms_course_id) publisher_course = publisher_course_run.course discovery_course = discovery_course_run.course # pylint: disable=no-member assert discovery_course_run.title_override == publisher_course_run.title_override assert discovery_course_run.short_description_override is None assert discovery_course_run.full_description_override is None assert discovery_course_run.start == publisher_course_run.start assert discovery_course_run.end == publisher_course_run.end assert discovery_course_run.enrollment_start == publisher_course_run.enrollment_start assert discovery_course_run.enrollment_end == publisher_course_run.enrollment_end assert discovery_course_run.pacing_type == publisher_course_run.pacing_type assert discovery_course_run.min_effort == publisher_course_run.min_effort assert discovery_course_run.max_effort == publisher_course_run.max_effort assert discovery_course_run.language == publisher_course_run.language assert discovery_course_run.weeks_to_complete == publisher_course_run.length assert discovery_course_run.learner_testimonials == publisher_course.learner_testimonial expected = set(publisher_course_run.transcript_languages.all()) assert set(discovery_course_run.transcript_languages.all()) == expected assert set(discovery_course_run.staff.all()) == set( publisher_course_run.staff.all()) assert discovery_course.canonical_course_run == discovery_course_run assert discovery_course.partner == partner assert discovery_course.title == publisher_course.title assert discovery_course.short_description == publisher_course.short_description assert discovery_course.full_description == publisher_course.full_description assert discovery_course.level_type == publisher_course.level_type assert discovery_course.video == Video.objects.get( src=publisher_course.video_link) assert discovery_course.image.name is not None assert discovery_course.image.url is not None assert discovery_course.image.file is not None assert discovery_course.image.small.url is not None assert discovery_course.image.small.file is not None assert discovery_course.outcome == publisher_course.expected_learnings assert discovery_course.prerequisites_raw == publisher_course.prerequisites assert discovery_course.syllabus_raw == publisher_course.syllabus expected = list(publisher_course_run.course.organizations.all()) assert list(discovery_course.authoring_organizations.all()) == expected expected = { publisher_course.primary_subject, publisher_course.secondary_subject } assert set(discovery_course.subjects.all()) == expected common_seat_kwargs = { 'course_run': discovery_course_run, 'currency': currency, } DiscoverySeat.objects.get(type=DiscoverySeat.AUDIT, upgrade_deadline__isnull=True, **common_seat_kwargs) DiscoverySeat.objects.get(type=DiscoverySeat.PROFESSIONAL, upgrade_deadline__isnull=True, price=professional_seat.price, **common_seat_kwargs) DiscoverySeat.objects.get( type=DiscoverySeat.VERIFIED, upgrade_deadline=verified_seat.upgrade_deadline, price=verified_seat.price, **common_seat_kwargs)