Commit 22af2b75 by Awais Qureshi Committed by Will Daly

ECOM-890: Update invoice data model.

ECOM-891: Allow tracking of invoice transactions.

Authors: Awais Qureshi and Aamir Khan
parent 6fa7815f
......@@ -299,8 +299,14 @@ class DashboardTest(ModuleStoreTestCase):
recipient_name='Testw_1', recipient_email='test2@test.com', internal_reference="A",
course_id=self.course.id, is_valid=False
)
invoice_item = shoppingcart.models.CourseRegistrationCodeInvoiceItem.objects.create(
invoice=sale_invoice_1,
qty=1,
unit_price=1234.32,
course_id=self.course.id
)
course_reg_code = shoppingcart.models.CourseRegistrationCode(
code="abcde", course_id=self.course.id, created_by=self.user, invoice=sale_invoice_1, mode_slug='honor'
code="abcde", course_id=self.course.id, created_by=self.user, invoice=sale_invoice_1, invoice_item=invoice_item, mode_slug='honor'
)
course_reg_code.save()
......
......@@ -465,8 +465,8 @@ def is_course_blocked(request, redeemed_registration_codes, course_key):
# registration codes may be generated via Bulk Purchase Scenario
# we have to check only for the invoice generated registration codes
# that their invoice is valid or not
if redeemed_registration.invoice:
if not getattr(redeemed_registration.invoice, 'is_valid'):
if redeemed_registration.invoice_item:
if not getattr(redeemed_registration.invoice_item.invoice, 'is_valid'):
blocked = True
# disabling email notifications for unpaid registration courses
Optout.objects.get_or_create(user=request.user, course_id=course_key)
......
......@@ -27,6 +27,7 @@ import string # pylint: disable=deprecated-module
import random
import unicodecsv
import urllib
import decimal
from student import auth
from student.roles import CourseSalesAdminRole
from util.file import store_uploaded_file, course_and_time_based_filename_generator, FileValidationException, UniversalNewlineIterator
......@@ -49,7 +50,14 @@ from django_comment_common.models import (
)
from edxmako.shortcuts import render_to_response, render_to_string
from courseware.models import StudentModule
from shoppingcart.models import Coupon, CourseRegistrationCode, RegistrationCodeRedemption, Invoice, CourseMode
from shoppingcart.models import (
Coupon,
CourseRegistrationCode,
RegistrationCodeRedemption,
Invoice,
CourseMode,
CourseRegistrationCodeInvoiceItem,
)
from student.models import CourseEnrollment, unique_id_for_user, anonymous_id_for_user
import instructor_task.api
from instructor_task.api_helper import AlreadyRunningError
......@@ -885,9 +893,13 @@ def sale_validation(request, course_id):
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
try:
obj_invoice = Invoice.objects.select_related('is_valid').get(id=invoice_number, course_id=course_id)
except Invoice.DoesNotExist:
return HttpResponseNotFound(_("Invoice number '{0}' does not exist.").format(invoice_number))
obj_invoice = CourseRegistrationCodeInvoiceItem.objects.select_related('invoice').get(
invoice_id=invoice_number,
course_id=course_id
)
obj_invoice = obj_invoice.invoice
except CourseRegistrationCodeInvoiceItem.DoesNotExist: # Check for old type invoices
return HttpResponseNotFound(_("Invoice number '{0}' does not exist.".format(invoice_number)))
if event_type == "invalidate":
return invalidate_invoice(obj_invoice)
......@@ -1053,7 +1065,7 @@ def get_coupon_codes(request, course_id): # pylint: disable=unused-argument
return instructor_analytics.csvs.create_csv_response('Coupons.csv', header, data_rows)
def save_registration_code(user, course_id, mode_slug, invoice=None, order=None):
def save_registration_code(user, course_id, mode_slug, invoice=None, order=None, invoice_item=None):
"""
recursive function that generate a new code every time and saves in the Course Registration Table
if validation check passes
......@@ -1064,6 +1076,7 @@ def save_registration_code(user, course_id, mode_slug, invoice=None, order=None)
mode_slug (str): The Course Mode Slug associated with any enrollment made by these codes.
invoice (Invoice): (Optional) The associated invoice for this code.
order (Order): (Optional) The associated order for this code.
invoice_item (CourseRegistrationCodeInvoiceItem) : (Optional) The associated CourseRegistrationCodeInvoiceItem
Returns:
The newly created CourseRegistrationCode.
......@@ -1074,7 +1087,9 @@ def save_registration_code(user, course_id, mode_slug, invoice=None, order=None)
# check if the generated code is in the Coupon Table
matching_coupons = Coupon.objects.filter(code=code, is_active=True)
if matching_coupons:
return save_registration_code(user, course_id, invoice, order)
return save_registration_code(
user, course_id, mode_slug, invoice=invoice, order=order, invoice_item=invoice_item
)
course_registration = CourseRegistrationCode(
code=code,
......@@ -1082,13 +1097,16 @@ def save_registration_code(user, course_id, mode_slug, invoice=None, order=None)
created_by=user,
invoice=invoice,
order=order,
mode_slug=mode_slug
mode_slug=mode_slug,
invoice_item=invoice_item
)
try:
course_registration.save()
return course_registration
except IntegrityError:
return save_registration_code(user, course_id, invoice, order)
return save_registration_code(
user, course_id, mode_slug, invoice=invoice, order=order, invoice_item=invoice_item
)
def registration_codes_csv(file_name, codes_list, csv_type=None):
......@@ -1130,11 +1148,13 @@ def get_registration_codes(request, course_id): # pylint: disable=unused-argume
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
#filter all the course registration codes
registration_codes = CourseRegistrationCode.objects.filter(course_id=course_id).order_by('invoice__company_name')
registration_codes = CourseRegistrationCode.objects.filter(
course_id=course_id
).order_by('invoice_item__invoice__company_name')
company_name = request.POST['download_company_name']
if company_name:
registration_codes = registration_codes.filter(invoice__company_name=company_name)
registration_codes = registration_codes.filter(invoice_item__invoice__company_name=company_name)
csv_type = 'download'
return registration_codes_csv("Registration_Codes.csv", registration_codes, csv_type)
......@@ -1160,7 +1180,21 @@ def generate_registration_codes(request, course_id):
company_name = request.POST['company_name']
company_contact_name = request.POST['company_contact_name']
company_contact_email = request.POST['company_contact_email']
sale_price = request.POST['sale_price']
unit_price = request.POST['unit_price']
try:
unit_price = (
decimal.Decimal(unit_price)
).quantize(
decimal.Decimal('.01'),
rounding=decimal.ROUND_DOWN
)
except decimal.InvalidOperation:
return HttpResponse(
status=400,
content=_(u"Could not parse amount as a decimal")
)
recipient_name = request.POST['recipient_name']
recipient_email = request.POST['recipient_email']
address_line_1 = request.POST['address_line_1']
......@@ -1177,6 +1211,7 @@ def generate_registration_codes(request, course_id):
recipient_list.append(request.user.email)
invoice_copy = True
sale_price = unit_price * course_code_number
UserPreference.set_preference(request.user, INVOICE_KEY, invoice_copy)
sale_invoice = Invoice.objects.create(
total_amount=sale_price,
......@@ -1197,6 +1232,13 @@ def generate_registration_codes(request, course_id):
customer_reference_number=customer_reference_number
)
invoice_item = CourseRegistrationCodeInvoiceItem.objects.create(
invoice=sale_invoice,
qty=course_code_number,
unit_price=unit_price,
course_id=course_id
)
course = get_course_by_id(course_id, depth=0)
paid_modes = CourseMode.paid_modes_for_course(course_id)
......@@ -1217,7 +1259,7 @@ def generate_registration_codes(request, course_id):
registration_codes = []
for __ in range(course_code_number): # pylint: disable=redefined-outer-name
generated_registration_code = save_registration_code(
request.user, course_id, course_mode.slug, sale_invoice, order=None
request.user, course_id, course_mode.slug, invoice=sale_invoice, order=None, invoice_item=invoice_item
)
registration_codes.append(generated_registration_code)
......@@ -1309,13 +1351,17 @@ def active_registration_codes(request, course_id): # pylint: disable=unused-arg
course_id = SlashSeparatedCourseKey.from_deprecated_string(course_id)
# find all the registration codes in this course
registration_codes_list = CourseRegistrationCode.objects.filter(course_id=course_id).order_by('invoice__company_name')
registration_codes_list = CourseRegistrationCode.objects.filter(
course_id=course_id
).order_by('invoice_item__invoice__company_name')
company_name = request.POST['active_company_name']
if company_name:
registration_codes_list = registration_codes_list.filter(invoice__company_name=company_name)
registration_codes_list = registration_codes_list.filter(invoice_item__invoice__company_name=company_name)
# find the redeemed registration codes if any exist in the db
code_redemption_set = RegistrationCodeRedemption.objects.select_related('registration_code').filter(registration_code__course_id=course_id)
code_redemption_set = RegistrationCodeRedemption.objects.select_related(
'registration_code', 'registration_code__invoice_item__invoice'
).filter(registration_code__course_id=course_id)
if code_redemption_set.exists():
redeemed_registration_codes = [code.registration_code.code for code in code_redemption_set]
# exclude the redeemed registration codes from the registration codes list and you will get
......@@ -1346,11 +1392,11 @@ def spent_registration_codes(request, course_id): # pylint: disable=unused-argu
# you will get a list of all the spent(Redeemed) Registration Codes
spent_codes_list = CourseRegistrationCode.objects.filter(
course_id=course_id, code__in=redeemed_registration_codes
).order_by('invoice__company_name')
).order_by('invoice_item__invoice__company_name').select_related('invoice_item__invoice')
company_name = request.POST['spent_company_name']
if company_name:
spent_codes_list = spent_codes_list.filter(invoice__company_name=company_name) # pylint: disable=maybe-no-member
spent_codes_list = spent_codes_list.filter(invoice_item__invoice__company_name=company_name) # pylint: disable=maybe-no-member
csv_type = 'spent'
return registration_codes_csv("Spent_Registration_Codes.csv", spent_codes_list, csv_type)
......
......@@ -6,7 +6,7 @@ Serve miscellaneous course and student data
import json
from shoppingcart.models import (
PaidCourseRegistration, CouponRedemption, Invoice, CourseRegCodeItem,
OrderTypes, RegistrationCodeRedemption, CourseRegistrationCode
OrderTypes, RegistrationCodeRedemption, CourseRegistrationCode, CourseRegistrationCodeInvoiceItem
)
from django.db.models import Q
from django.conf import settings
......@@ -110,22 +110,25 @@ def sale_record_features(course_id, features):
{'company_name': 'group_C', 'total_codes': '3', total_amount:'total_amount3 in decimal'.}
]
"""
sales = Invoice.objects.filter(course_id=course_id)
sales = CourseRegistrationCodeInvoiceItem.objects.select_related('invoice').filter(course_id=course_id)
def sale_records_info(sale, features):
""" convert sales records to dictionary """
"""
Convert sales records to dictionary
"""
invoice = sale.invoice
sale_features = [x for x in SALE_FEATURES if x in features]
course_reg_features = [x for x in COURSE_REGISTRATION_FEATURES if x in features]
# Extracting sale information
sale_dict = dict((feature, getattr(sale, feature))
sale_dict = dict((feature, getattr(invoice, feature))
for feature in sale_features)
total_used_codes = RegistrationCodeRedemption.objects.filter(
registration_code__in=sale.courseregistrationcode_set.all()
).count()
sale_dict.update({"invoice_number": getattr(sale, 'id')})
sale_dict.update({"invoice_number": getattr(invoice, 'id')})
sale_dict.update({"total_codes": sale.courseregistrationcode_set.all().count()})
sale_dict.update({'total_used_codes': total_used_codes})
......@@ -261,11 +264,11 @@ def course_registration_features(features, registration_codes, csv_type):
course_registration_dict = dict((feature, getattr(registration_code, feature)) for feature in registration_features)
course_registration_dict['company_name'] = None
if registration_code.invoice:
course_registration_dict['company_name'] = getattr(registration_code.invoice, 'company_name')
if registration_code.invoice_item:
course_registration_dict['company_name'] = getattr(registration_code.invoice_item.invoice, 'company_name')
course_registration_dict['redeemed_by'] = None
if registration_code.invoice:
sale_invoice = Invoice.objects.get(id=registration_code.invoice_id)
if registration_code.invoice_item:
sale_invoice = registration_code.invoice_item.invoice
course_registration_dict['invoice_id'] = sale_invoice.id
course_registration_dict['purchaser'] = sale_invoice.recipient_name
course_registration_dict['customer_reference_number'] = sale_invoice.customer_reference_number
......
......@@ -11,7 +11,7 @@ from student.tests.factories import UserFactory, CourseModeFactory
from opaque_keys.edx.locations import SlashSeparatedCourseKey
from shoppingcart.models import (
CourseRegistrationCode, RegistrationCodeRedemption, Order,
Invoice, Coupon, CourseRegCodeItem, CouponRedemption
Invoice, Coupon, CourseRegCodeItem, CouponRedemption, CourseRegistrationCodeInvoiceItem
)
from course_modes.models import CourseMode
from instructor_analytics.basic import (
......@@ -147,10 +147,16 @@ class TestCourseSaleRecordsAnalyticsBasic(ModuleStoreTestCase):
company_contact_email='test@company.com', recipient_name='Testw_1', recipient_email='test2@test.com',
customer_reference_number='2Fwe23S', internal_reference="ABC", course_id=self.course.id
)
invoice_item = CourseRegistrationCodeInvoiceItem.objects.create(
invoice=sale_invoice,
qty=1,
unit_price=1234.32,
course_id=self.course.id
)
for i in range(5):
course_code = CourseRegistrationCode(
code="test_code{}".format(i), course_id=self.course.id.to_deprecated_string(),
created_by=self.instructor, invoice=sale_invoice, mode_slug='honor'
created_by=self.instructor, invoice=sale_invoice, invoice_item=invoice_item, mode_slug='honor'
)
course_code.save()
......@@ -272,7 +278,7 @@ class TestCourseRegistrationCodeAnalyticsBasic(ModuleStoreTestCase):
kwargs={'course_id': self.course.id.to_deprecated_string()})
data = {
'total_registration_codes': 12, 'company_name': 'Test Group', 'sale_price': 122.45,
'total_registration_codes': 12, 'company_name': 'Test Group', 'unit_price': 122.45,
'company_contact_name': 'TestName', 'company_contact_email': 'test@company.com', 'recipient_name': 'Test123',
'recipient_email': 'test@123.com', 'address_line_1': 'Portland Street', 'address_line_2': '',
'address_line_3': '', 'city': '', 'state': '', 'zip': '', 'country': '',
......@@ -306,11 +312,17 @@ class TestCourseRegistrationCodeAnalyticsBasic(ModuleStoreTestCase):
)
self.assertIn(
course_registration['company_name'],
[getattr(registration_code.invoice, 'company_name') for registration_code in registration_codes]
[
getattr(registration_code.invoice_item.invoice, 'company_name')
for registration_code in registration_codes
]
)
self.assertIn(
course_registration['invoice_id'],
[registration_code.invoice_id for registration_code in registration_codes]
[
registration_code.invoice_item.invoice_id
for registration_code in registration_codes
]
)
def test_coupon_codes_features(self):
......
"""
Allows django admin site to add PaidCourseRegistrationAnnotations
"""
"""Django admin interface for the shopping cart models. """
from ratelimitbackend import admin
from shoppingcart.models import (
PaidCourseRegistrationAnnotation, Coupon, DonationConfiguration
PaidCourseRegistrationAnnotation,
Coupon,
DonationConfiguration,
Invoice,
CourseRegistrationCodeInvoiceItem,
InvoiceTransaction
)
......@@ -49,6 +52,128 @@ class SoftDeleteCouponAdmin(admin.ModelAdmin):
really_delete_selected.short_description = "Delete s selected entries"
class CourseRegistrationCodeInvoiceItemInline(admin.StackedInline):
"""Admin for course registration code invoice items.
Displayed inline within the invoice admin UI.
"""
model = CourseRegistrationCodeInvoiceItem
extra = 0
can_delete = False
readonly_fields = (
'qty',
'unit_price',
'currency',
'course_id',
)
def has_add_permission(self, request):
return False
class InvoiceTransactionInline(admin.StackedInline):
"""Admin for invoice transactions.
Displayed inline within the invoice admin UI.
"""
model = InvoiceTransaction
extra = 0
readonly_fields = (
'created',
'modified',
'created_by',
'last_modified_by'
)
class InvoiceAdmin(admin.ModelAdmin):
"""Admin for invoices.
This is intended for the internal finance team
to be able to view and update invoice information,
including payments and refunds.
"""
date_hierarchy = 'created'
can_delete = False
readonly_fields = ('created', 'modified')
search_fields = (
'internal_reference',
'customer_reference_number',
'company_name',
)
fieldsets = (
(
None, {
'fields': (
'internal_reference',
'customer_reference_number',
'created',
'modified',
)
}
),
(
'Billing Information', {
'fields': (
'company_name',
'company_contact_name',
'company_contact_email',
'recipient_name',
'recipient_email',
'address_line_1',
'address_line_2',
'address_line_3',
'city',
'state',
'zip',
'country'
)
}
)
)
readonly_fields = (
'internal_reference',
'customer_reference_number',
'created',
'modified',
'company_name',
'company_contact_name',
'company_contact_email',
'recipient_name',
'recipient_email',
'address_line_1',
'address_line_2',
'address_line_3',
'city',
'state',
'zip',
'country'
)
inlines = [
CourseRegistrationCodeInvoiceItemInline,
InvoiceTransactionInline
]
def save_formset(self, request, form, formset, change):
"""Save the user who created and modified invoice transactions. """
instances = formset.save(commit=False)
for instance in instances:
if isinstance(instance, InvoiceTransaction):
if not hasattr(instance, 'created_by'):
instance.created_by = request.user
instance.last_modified_by = request.user
instance.save()
def has_add_permission(self, request):
return False
def has_delete_permission(self, request, obj=None):
return False
admin.site.register(PaidCourseRegistrationAnnotation)
admin.site.register(Coupon, SoftDeleteCouponAdmin)
admin.site.register(DonationConfiguration)
admin.site.register(Invoice, InvoiceAdmin)
......@@ -18,7 +18,7 @@ from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.core.mail import send_mail
from django.contrib.auth.models import User
from django.utils.translation import ugettext as _
from django.utils.translation import ugettext as _, ugettext_lazy
from django.db import transaction
from django.db.models import Sum
from django.core.urlresolvers import reverse
......@@ -773,11 +773,11 @@ class OrderItem(TimeStampedModel):
self.save()
class Invoice(models.Model):
class Invoice(TimeStampedModel):
"""
This table capture all the information needed to support "invoicing"
which is when a user wants to purchase Registration Codes,
but will not do so via a Credit Card transaction.
This table capture all the information needed to support "invoicing"
which is when a user wants to purchase Registration Codes,
but will not do so via a Credit Card transaction.
"""
company_name = models.CharField(max_length=255, db_index=True)
company_contact_name = models.CharField(max_length=255)
......@@ -785,16 +785,39 @@ class Invoice(models.Model):
recipient_name = models.CharField(max_length=255)
recipient_email = models.CharField(max_length=255)
address_line_1 = models.CharField(max_length=255)
address_line_2 = models.CharField(max_length=255, null=True)
address_line_3 = models.CharField(max_length=255, null=True)
address_line_2 = models.CharField(max_length=255, null=True, blank=True)
address_line_3 = models.CharField(max_length=255, null=True, blank=True)
city = models.CharField(max_length=255, null=True)
state = models.CharField(max_length=255, null=True)
zip = models.CharField(max_length=15, null=True)
country = models.CharField(max_length=64, null=True)
course_id = CourseKeyField(max_length=255, db_index=True)
# This field has been deprecated.
# The total amount can now be calculated as the sum
# of each invoice item associated with the invoice.
# For backwards compatibility, this field is maintained
# and written to during invoice creation.
total_amount = models.FloatField()
internal_reference = models.CharField(max_length=255, null=True)
customer_reference_number = models.CharField(max_length=63, null=True)
# This field has been deprecated in order to support
# invoices for items that are not course-related.
# Although this field is still maintained for backwards
# compatibility, you should use CourseRegistrationCodeInvoiceItem
# to look up the course ID for purchased redeem codes.
course_id = CourseKeyField(max_length=255, db_index=True)
internal_reference = models.CharField(
max_length=255,
null=True,
blank=True,
help_text=ugettext_lazy("Internal reference code for this invoice.")
)
customer_reference_number = models.CharField(
max_length=63,
null=True,
blank=True,
help_text=ugettext_lazy("Customer's reference code for this invoice.")
)
is_valid = models.BooleanField(default=True)
def generate_pdf_invoice(self, course, course_price, quantity, sale_price):
......@@ -824,6 +847,125 @@ class Invoice(models.Model):
return pdf_buffer
def __unicode__(self):
label = (
unicode(self.internal_reference)
if self.internal_reference
else u"No label"
)
created = (
self.created.strftime("%Y-%m-%d") # pylint: disable=no-member
if self.created
else u"No date"
)
return u"{label} ({date_created})".format(
label=label, date_created=created
)
INVOICE_TRANSACTION_STATUSES = (
# A payment/refund is in process, but money has not yet been transferred
('started', 'started'),
# A payment/refund has completed successfully
# This should be set ONLY once money has been successfully exchanged.
('completed', 'completed'),
# A payment/refund was promised, but was cancelled before
# money had been transferred. An example would be
# cancelling a refund check before the recipient has
# a chance to deposit it.
('cancelled', 'cancelled')
)
class InvoiceTransaction(TimeStampedModel):
"""Record payment and refund information for invoices.
There are two expected use cases:
1) We send an invoice to someone, and they send us a check.
We then manually create an invoice transaction to represent
the payment.
2) We send an invoice to someone, and they pay us. Later, we
need to issue a refund for the payment. We manually
create a transaction with a negative amount to represent
the refund.
"""
invoice = models.ForeignKey(Invoice)
amount = models.DecimalField(
default=0.0, decimal_places=2, max_digits=30,
help_text=ugettext_lazy(
"The amount of the transaction. Use positive amounts for payments"
" and negative amounts for refunds."
)
)
currency = models.CharField(
default="usd",
max_length=8,
help_text=ugettext_lazy("Lower-case ISO currency codes")
)
comments = models.TextField(
null=True,
blank=True,
help_text=ugettext_lazy("Optional: provide additional information for this transaction")
)
status = models.CharField(
max_length=32,
default='started',
choices=INVOICE_TRANSACTION_STATUSES,
help_text=ugettext_lazy(
"The status of the payment or refund. "
"'started' means that payment is expected, but money has not yet been transferred. "
"'completed' means that the payment or refund was received. "
"'cancelled' means that payment or refund was expected, but was cancelled before money was transferred. "
)
)
created_by = models.ForeignKey(User)
last_modified_by = models.ForeignKey(User, related_name='last_modified_by_user')
class InvoiceItem(TimeStampedModel):
"""
This is the basic interface for invoice items.
Each invoice item represents a "line" in the invoice.
For example, in an invoice for course registration codes,
there might be an invoice item representing 10 registration
codes for the DemoX course.
"""
objects = InheritanceManager()
invoice = models.ForeignKey(Invoice, db_index=True)
qty = models.IntegerField(
default=1,
help_text=ugettext_lazy("The number of items sold.")
)
unit_price = models.DecimalField(
default=0.0,
decimal_places=2,
max_digits=30,
help_text=ugettext_lazy("The price per item sold, including discounts.")
)
currency = models.CharField(
default="usd",
max_length=8,
help_text=ugettext_lazy("Lower-case ISO currency codes")
)
class CourseRegistrationCodeInvoiceItem(InvoiceItem):
"""
This is an invoice item that represents a payment for
a course registration.
"""
course_id = CourseKeyField(max_length=128, db_index=True)
class CourseRegistrationCode(models.Model):
"""
......@@ -835,9 +977,14 @@ class CourseRegistrationCode(models.Model):
created_by = models.ForeignKey(User, related_name='created_by_user')
created_at = models.DateTimeField(default=datetime.now(pytz.utc))
order = models.ForeignKey(Order, db_index=True, null=True, related_name="purchase_order")
invoice = models.ForeignKey(Invoice, null=True)
mode_slug = models.CharField(max_length=100, null=True)
# For backwards compatibility, we maintain the FK to "invoice"
# In the future, we will remove this in favor of the FK
# to "invoice_item" (which can be used to look up the invoice).
invoice = models.ForeignKey(Invoice, null=True)
invoice_item = models.ForeignKey(CourseRegistrationCodeInvoiceItem, null=True)
class RegistrationCodeRedemption(models.Model):
"""
......@@ -1227,7 +1374,7 @@ class CourseRegCodeItem(OrderItem):
# is in another PR (for another feature)
from instructor.views.api import save_registration_code
for i in range(total_registration_codes): # pylint: disable=unused-variable
save_registration_code(self.user, self.course_id, self.mode, invoice=None, order=self.order)
save_registration_code(self.user, self.course_id, self.mode, order=self.order)
log.info("Enrolled {0} in paid course {1}, paid ${2}"
.format(self.user.email, self.course_id, self.line_cost)) # pylint: disable=no-member
......
......@@ -1518,7 +1518,7 @@ class RegistrationCodeRedemptionCourseEnrollment(ModuleStoreTestCase):
data = {
'total_registration_codes': 12, 'company_name': 'Test Group', 'company_contact_name': 'Test@company.com',
'company_contact_email': 'Test@company.com', 'sale_price': 122.45, 'recipient_name': 'Test123',
'company_contact_email': 'Test@company.com', 'unit_price': 122.45, 'recipient_name': 'Test123',
'recipient_email': 'test@123.com', 'address_line_1': 'Portland Street',
'address_line_2': '', 'address_line_3': '', 'city': '', 'state': '', 'zip': '', 'country': '',
'customer_reference_number': '123A23F', 'internal_reference': '', 'invoice': ''
......
......@@ -1664,7 +1664,7 @@ input[name="subject"] {
height: auto;
}
}
li#generate-registration-modal-field-country ~ li#generate-registration-modal-field-total-price,
li#generate-registration-modal-field-country ~ li#generate-registration-modal-field-unit-price,
li#generate-registration-modal-field-country ~ li#generate-registration-modal-field-internal-reference {
@include margin-left(0px !important);
@include margin-right(15px !important);
......
......@@ -296,7 +296,7 @@
var total_registration_codes = $('input[name="total_registration_codes"]').val();
var recipient_name = $('input[name="recipient_name"]').val();
var recipient_email = $('input[name="recipient_email"]').val();
var sale_price = $('input[name="sale_price"]').val();
var unit_price = $('input[name="unit_price"]').val();
var company_name = $('input[name="company_name"]').val();
var company_contact_name = $('input[name="company_contact_name"]').val();
var company_contact_email = $('input[name="company_contact_email"]').val();
......@@ -305,91 +305,91 @@
if (company_name == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the company name');
registration_code_error.text("${_('Please enter the company name')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (($.isNumeric(company_name))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the non-numeric value for company name');
registration_code_error.text("${_('Please enter the non-numeric value for company name')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (company_contact_name == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the company contact name');
registration_code_error.text("${_('Please enter the company contact name')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (($.isNumeric(company_contact_name))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the non-numeric value for company contact name');
registration_code_error.text("${_('Please enter the non-numeric value for company contact name')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (company_contact_email == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the company contact email');
registration_code_error.text("${_('Please enter the company contact email')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (!(validateEmail(company_contact_email))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the valid email address');
registration_code_error.text("${_('Please enter the valid email address')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (recipient_name == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the recipient name');
registration_code_error.text("${_('Please enter the recipient name')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (($.isNumeric(recipient_name))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the non-numeric value for recipient name');
registration_code_error.text("${_('Please enter the non-numeric value for recipient name')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (recipient_email == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the recipient email');
registration_code_error.text("${_('Please enter the recipient email')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (!(validateEmail(recipient_email))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the valid email address');
registration_code_error.text("${_('Please enter the valid email address')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (address_line == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the billing address');
registration_code_error.text("${_('Please enter the billing address')}");
generate_registration_button.removeAttr('disabled');
return false;
}
if (sale_price == '') {
if (unit_price == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the sale price');
registration_code_error.text("${_('Please enter the unit price')}");
generate_registration_button.removeAttr('disabled');
return false
}
if (!($.isNumeric(sale_price))) {
if (!($.isNumeric(unit_price))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the numeric value for sale price');
registration_code_error.text("${_('Please enter the numeric value for unit price')}");
generate_registration_button.removeAttr('disabled');
return false
}
if (total_registration_codes == '') {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the total registration codes');
registration_code_error.text("${_('Please enter the number of enrollment codes')}");
generate_registration_button.removeAttr('disabled');
return false
}
if (!($.isNumeric(total_registration_codes))) {
registration_code_error.attr('style', 'display: block !important');
registration_code_error.text('Please enter the numeric value for total registration codes');
registration_code_error.text("${_('Please enter the numeric value for number of enrollment codes')}");
generate_registration_button.removeAttr('disabled');
return false;
}
......@@ -600,7 +600,7 @@
$('input[name="country"]').val('');
$('input[name="customer_reference_number"]').val('');
$('input[name="recipient_name"]').val('');
$('input[name="sale_price"]').val('');
$('input[name="unit_price"]').val('');
$('input[name="recipient_email"]').val('');
$('input[name="company_contact_name"]').val('');
$('input[name="company_contact_email"]').val('');
......
......@@ -102,12 +102,12 @@
</span>
</li>
<div class="clearfix"></div>
<li class="field required text" id="generate-registration-modal-field-total-price">
<label for="id_sale_price" class="required text">${_("Sale Price")}</label>
<input class="field required" id="id_sale_price" type="text" name="sale_price"
<li class="field required text" id="generate-registration-modal-field-unit-price">
<label for="id_unit_price" class="required text">${_("Unit Price")}</label>
<input class="field required" id="id_unit_price" type="text" name="unit_price"
aria-required="true" />
<span class="tip-text">
${_("The total price for all enrollments purchased")}
${_("The price per enrollment purchased")}
</span>
</li>
<li class="field required text" id="generate-registration-modal-field-total-codes">
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment