|
|
|
|
@@ -1,6 +1,8 @@
|
|
|
|
|
# pylint: disable=arguments-differ
|
|
|
|
|
""" Models for the shopping cart and assorted purchase types """
|
|
|
|
|
|
|
|
|
|
from __future__ import absolute_import
|
|
|
|
|
|
|
|
|
|
import csv
|
|
|
|
|
import json
|
|
|
|
|
import logging
|
|
|
|
|
@@ -12,6 +14,7 @@ from decimal import Decimal
|
|
|
|
|
from io import BytesIO
|
|
|
|
|
|
|
|
|
|
import pytz
|
|
|
|
|
import six
|
|
|
|
|
from boto.exception import BotoServerError # this is a super-class of SESError and catches connection errors
|
|
|
|
|
from config_models.models import ConfigurationModel
|
|
|
|
|
from django.conf import settings
|
|
|
|
|
@@ -19,22 +22,22 @@ from django.contrib.auth.models import User
|
|
|
|
|
from django.core.exceptions import ObjectDoesNotExist
|
|
|
|
|
from django.core.mail import send_mail
|
|
|
|
|
from django.core.mail.message import EmailMessage
|
|
|
|
|
from django.urls import reverse
|
|
|
|
|
from django.db import models, transaction
|
|
|
|
|
from django.db.models import Count, F, Q, Sum
|
|
|
|
|
from django.db.models.signals import post_delete, post_save
|
|
|
|
|
from django.dispatch import receiver
|
|
|
|
|
from django.urls import reverse
|
|
|
|
|
from django.utils.translation import ugettext as _
|
|
|
|
|
from django.utils.translation import ugettext_lazy
|
|
|
|
|
from model_utils.managers import InheritanceManager
|
|
|
|
|
from model_utils.models import TimeStampedModel
|
|
|
|
|
from opaque_keys.edx.django.models import CourseKeyField
|
|
|
|
|
from six import text_type
|
|
|
|
|
from six.moves import range
|
|
|
|
|
|
|
|
|
|
from course_modes.models import CourseMode
|
|
|
|
|
from courseware.courses import get_course_by_id
|
|
|
|
|
from edxmako.shortcuts import render_to_string
|
|
|
|
|
from eventtracking import tracker
|
|
|
|
|
from openedx.core.djangoapps.site_configuration import helpers as configuration_helpers
|
|
|
|
|
from openedx.core.djangolib.markup import HTML, Text
|
|
|
|
|
from shoppingcart.pdf import PDFInvoice
|
|
|
|
|
@@ -349,7 +352,7 @@ class Order(models.Model):
|
|
|
|
|
for registration_code in registration_codes:
|
|
|
|
|
redemption_url = reverse('register_code_redemption', args=[registration_code.code])
|
|
|
|
|
url = '{base_url}{redemption_url}'.format(base_url=site_name, redemption_url=redemption_url)
|
|
|
|
|
csv_writer.writerow([unicode(course.display_name).encode("utf-8"), registration_code.code, url])
|
|
|
|
|
csv_writer.writerow([six.text_type(course.display_name).encode("utf-8"), registration_code.code, url])
|
|
|
|
|
|
|
|
|
|
return csv_file, course_names
|
|
|
|
|
|
|
|
|
|
@@ -596,10 +599,10 @@ class Order(models.Model):
|
|
|
|
|
we throw an UnexpectedOrderItemStatus error)
|
|
|
|
|
"""
|
|
|
|
|
# if an order is already retired, no-op:
|
|
|
|
|
if self.status in ORDER_STATUS_MAP.values():
|
|
|
|
|
if self.status in list(ORDER_STATUS_MAP.values()):
|
|
|
|
|
return
|
|
|
|
|
|
|
|
|
|
if self.status not in ORDER_STATUS_MAP.keys():
|
|
|
|
|
if self.status not in list(ORDER_STATUS_MAP.keys()):
|
|
|
|
|
raise InvalidStatusToRetire(
|
|
|
|
|
u"order status {order_status} is not 'paying' or 'cart'".format(
|
|
|
|
|
order_status=self.status
|
|
|
|
|
@@ -960,7 +963,7 @@ class Invoice(TimeStampedModel):
|
|
|
|
|
|
|
|
|
|
def __unicode__(self):
|
|
|
|
|
label = (
|
|
|
|
|
unicode(self.internal_reference)
|
|
|
|
|
six.text_type(self.internal_reference)
|
|
|
|
|
if self.internal_reference
|
|
|
|
|
else u"No label"
|
|
|
|
|
)
|
|
|
|
|
@@ -1079,7 +1082,7 @@ class InvoiceTransaction(TimeStampedModel):
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
return {
|
|
|
|
|
'amount': unicode(self.amount),
|
|
|
|
|
'amount': six.text_type(self.amount),
|
|
|
|
|
'currency': self.currency,
|
|
|
|
|
'comments': self.comments,
|
|
|
|
|
'status': self.status,
|
|
|
|
|
@@ -1133,7 +1136,7 @@ class InvoiceItem(TimeStampedModel):
|
|
|
|
|
"""
|
|
|
|
|
return {
|
|
|
|
|
'qty': self.qty,
|
|
|
|
|
'unit_price': unicode(self.unit_price),
|
|
|
|
|
'unit_price': six.text_type(self.unit_price),
|
|
|
|
|
'currency': self.currency
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -1161,7 +1164,7 @@ class CourseRegistrationCodeInvoiceItem(InvoiceItem):
|
|
|
|
|
|
|
|
|
|
"""
|
|
|
|
|
snapshot = super(CourseRegistrationCodeInvoiceItem, self).snapshot()
|
|
|
|
|
snapshot['course_id'] = unicode(self.course_id)
|
|
|
|
|
snapshot['course_id'] = six.text_type(self.course_id)
|
|
|
|
|
return snapshot
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1674,10 +1677,10 @@ class PaidCourseRegistration(OrderItem):
|
|
|
|
|
data = super(PaidCourseRegistration, self).analytics_data()
|
|
|
|
|
sku = data['sku']
|
|
|
|
|
if self.course_id != CourseKeyField.Empty:
|
|
|
|
|
data['name'] = unicode(self.course_id)
|
|
|
|
|
data['category'] = unicode(self.course_id.org)
|
|
|
|
|
data['name'] = six.text_type(self.course_id)
|
|
|
|
|
data['category'] = six.text_type(self.course_id.org)
|
|
|
|
|
if self.mode:
|
|
|
|
|
data['sku'] = sku + u'.' + unicode(self.mode)
|
|
|
|
|
data['sku'] = sku + u'.' + six.text_type(self.mode)
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -1841,10 +1844,10 @@ class CourseRegCodeItem(OrderItem):
|
|
|
|
|
data = super(CourseRegCodeItem, self).analytics_data()
|
|
|
|
|
sku = data['sku']
|
|
|
|
|
if self.course_id != CourseKeyField.Empty:
|
|
|
|
|
data['name'] = unicode(self.course_id)
|
|
|
|
|
data['category'] = unicode(self.course_id.org)
|
|
|
|
|
data['name'] = six.text_type(self.course_id)
|
|
|
|
|
data['category'] = six.text_type(self.course_id.org)
|
|
|
|
|
if self.mode:
|
|
|
|
|
data['sku'] = sku + u'.' + unicode(self.mode)
|
|
|
|
|
data['sku'] = sku + u'.' + six.text_type(self.mode)
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2033,7 +2036,7 @@ class CertificateItem(OrderItem):
|
|
|
|
|
|
|
|
|
|
if is_enrollment_mode_verified:
|
|
|
|
|
domain = configuration_helpers.get_value('SITE_NAME', settings.SITE_NAME)
|
|
|
|
|
path = reverse('verify_student_verify_now', kwargs={'course_id': unicode(self.course_id)})
|
|
|
|
|
path = reverse('verify_student_verify_now', kwargs={'course_id': six.text_type(self.course_id)})
|
|
|
|
|
verification_url = "http://{domain}{path}".format(domain=domain, path=path)
|
|
|
|
|
|
|
|
|
|
verification_reminder = _(
|
|
|
|
|
@@ -2107,10 +2110,10 @@ class CertificateItem(OrderItem):
|
|
|
|
|
data = super(CertificateItem, self).analytics_data()
|
|
|
|
|
sku = data['sku']
|
|
|
|
|
if self.course_id != CourseKeyField.Empty:
|
|
|
|
|
data['name'] = unicode(self.course_id)
|
|
|
|
|
data['category'] = unicode(self.course_id.org)
|
|
|
|
|
data['name'] = six.text_type(self.course_id)
|
|
|
|
|
data['category'] = six.text_type(self.course_id.org)
|
|
|
|
|
if self.mode:
|
|
|
|
|
data['sku'] = sku + u'.' + unicode(self.mode)
|
|
|
|
|
data['sku'] = sku + u'.' + six.text_type(self.mode)
|
|
|
|
|
return data
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@@ -2288,8 +2291,8 @@ class Donation(OrderItem):
|
|
|
|
|
"""
|
|
|
|
|
data = super(Donation, self).analytics_data()
|
|
|
|
|
if self.course_id != CourseKeyField.Empty:
|
|
|
|
|
data['name'] = unicode(self.course_id)
|
|
|
|
|
data['category'] = unicode(self.course_id.org)
|
|
|
|
|
data['name'] = six.text_type(self.course_id)
|
|
|
|
|
data['category'] = six.text_type(self.course_id.org)
|
|
|
|
|
else:
|
|
|
|
|
data['name'] = configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
|
|
|
|
|
data['category'] = configuration_helpers.get_value('PLATFORM_NAME', settings.PLATFORM_NAME)
|
|
|
|
|
|