Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
course-discovery
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
edx
course-discovery
Commits
e0081ed0
Commit
e0081ed0
authored
Mar 28, 2017
by
Ivan Ivic
Committed by
Ivan Ivic
Apr 07, 2017
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Enable eligible program functionality
LEARNER-275
parent
ba64068d
Hide whitespace changes
Inline
Side-by-side
Showing
11 changed files
with
363 additions
and
33 deletions
+363
-33
course_discovery/apps/api/serializers.py
+1
-1
course_discovery/apps/api/tests/test_serializers.py
+2
-1
course_discovery/apps/course_metadata/admin.py
+31
-6
course_discovery/apps/course_metadata/migrations/0051_program_one_click_purchase_enabled.py
+20
-0
course_discovery/apps/course_metadata/models.py
+62
-0
course_discovery/apps/course_metadata/tests/test_admin.py
+56
-3
course_discovery/apps/course_metadata/tests/test_models.py
+151
-0
course_discovery/conf/locale/en/LC_MESSAGES/django.mo
+0
-0
course_discovery/conf/locale/en/LC_MESSAGES/django.po
+19
-11
course_discovery/conf/locale/eo/LC_MESSAGES/django.mo
+0
-0
course_discovery/conf/locale/eo/LC_MESSAGES/django.po
+21
-11
No files found.
course_discovery/apps/api/serializers.py
View file @
e0081ed0
...
...
@@ -713,7 +713,7 @@ class MinimalProgramSerializer(serializers.ModelSerializer):
model
=
Program
fields
=
(
'uuid'
,
'title'
,
'subtitle'
,
'type'
,
'status'
,
'marketing_slug'
,
'marketing_url'
,
'banner_image'
,
'courses'
,
'authoring_organizations'
,
'card_image_url'
,
'courses'
,
'authoring_organizations'
,
'card_image_url'
,
'is_program_eligible_for_one_click_purchase'
,
)
read_only_fields
=
(
'uuid'
,
'marketing_url'
,
'banner_image'
)
...
...
course_discovery/apps/api/tests/test_serializers.py
View file @
e0081ed0
...
...
@@ -225,7 +225,7 @@ class MinimalCourseRunSerializerTests(TestCase):
'enrollment_end'
:
json_date_format
(
course_run
.
enrollment_end
),
'pacing_type'
:
course_run
.
pacing_type
,
'type'
:
course_run
.
type
,
'seats'
:
SeatSerializer
(
course_run
.
seats
,
many
=
True
)
.
data
'seats'
:
SeatSerializer
(
course_run
.
seats
,
many
=
True
)
.
data
,
}
def
test_data
(
self
):
...
...
@@ -601,6 +601,7 @@ class MinimalProgramSerializerTests(TestCase):
})
.
data
,
'authoring_organizations'
:
MinimalOrganizationSerializer
(
program
.
authoring_organizations
,
many
=
True
)
.
data
,
'card_image_url'
:
program
.
card_image_url
,
'is_program_eligible_for_one_click_purchase'
:
program
.
is_program_eligible_for_one_click_purchase
}
def
test_data
(
self
):
...
...
course_discovery/apps/course_metadata/admin.py
View file @
e0081ed0
...
...
@@ -10,6 +10,33 @@ from course_discovery.apps.course_metadata.publishers import ProgramPublisherExc
from
course_discovery.apps.course_metadata.utils
import
MarketingSiteAPIClientException
class
ProgramEligibilityFilter
(
admin
.
SimpleListFilter
):
title
=
_
(
'eligible for one-click purchase'
)
parameter_name
=
'eligible_for_one_click_purchase'
def
lookups
(
self
,
request
,
model_admin
):
# pragma: no cover
return
(
(
1
,
_
(
'Yes'
)),
(
0
,
_
(
'No'
))
)
def
queryset
(
self
,
request
,
queryset
):
"""
The queryset can be filtered to contain programs that are eligible for
one click purchase or to exclude them.
"""
value
=
self
.
value
()
if
value
is
None
:
return
queryset
program_ids
=
set
()
queryset
=
queryset
.
prefetch_related
(
'courses__course_runs'
)
for
program
in
queryset
:
if
program
.
is_program_eligible_for_one_click_purchase
==
bool
(
int
(
value
)):
program_ids
.
add
(
program
.
id
)
return
queryset
.
filter
(
pk__in
=
program_ids
)
class
SeatInline
(
admin
.
TabularInline
):
model
=
Seat
extra
=
1
...
...
@@ -81,7 +108,7 @@ class ProgramAdmin(admin.ModelAdmin):
form
=
ProgramAdminForm
inlines
=
[
FaqsInline
,
IndividualEndorsementInline
,
CorporateEndorsementsInline
]
list_display
=
(
'id'
,
'uuid'
,
'title'
,
'type'
,
'partner'
,
'status'
,)
list_filter
=
(
'partner'
,
'type'
,
'status'
,)
list_filter
=
(
'partner'
,
'type'
,
'status'
,
ProgramEligibilityFilter
,
)
ordering
=
(
'uuid'
,
'title'
,
'status'
)
readonly_fields
=
(
'uuid'
,
'custom_course_runs_display'
,
'excluded_course_runs'
,)
search_fields
=
(
'uuid'
,
'title'
,
'marketing_slug'
)
...
...
@@ -92,11 +119,9 @@ class ProgramAdmin(admin.ModelAdmin):
fields
=
(
'title'
,
'subtitle'
,
'status'
,
'type'
,
'partner'
,
'banner_image'
,
'banner_image_url'
,
'card_image_url'
,
'marketing_slug'
,
'overview'
,
'credit_redemption_overview'
,
'video'
,
'weeks_to_complete'
,
'min_hours_effort_per_week'
,
'max_hours_effort_per_week'
,
)
fields
+=
(
'courses'
,
'order_courses_by_start_date'
,
'custom_course_runs_display'
,
'excluded_course_runs'
,
'authoring_organizations'
,
'credit_backing_organizations'
'min_hours_effort_per_week'
,
'max_hours_effort_per_week'
,
'courses'
,
'order_courses_by_start_date'
,
'custom_course_runs_display'
,
'excluded_course_runs'
,
'authoring_organizations'
,
'credit_backing_organizations'
,
'one_click_purchase_enabled'
,
)
fields
+=
filter_horizontal
save_error
=
False
...
...
course_discovery/apps/course_metadata/migrations/0051_program_one_click_purchase_enabled.py
0 → 100644
View file @
e0081ed0
# -*- coding: utf-8 -*-
# Generated by Django 1.9.12 on 2017-04-05 12:06
from
__future__
import
unicode_literals
from
django.db
import
migrations
,
models
class
Migration
(
migrations
.
Migration
):
dependencies
=
[
(
'course_metadata'
,
'0050_person_profile_url'
),
]
operations
=
[
migrations
.
AddField
(
model_name
=
'program'
,
name
=
'one_click_purchase_enabled'
,
field
=
models
.
BooleanField
(
default
=
False
,
help_text
=
'Allow courses in this program to be purchased in a single transaction'
),
),
]
course_discovery/apps/course_metadata/models.py
View file @
e0081ed0
...
...
@@ -9,6 +9,7 @@ import pytz
import
waffle
from
django.db
import
models
,
transaction
from
django.db.models.query_utils
import
Q
from
django.utils
import
timezone
from
django.utils.functional
import
cached_property
from
django.utils.translation
import
ugettext_lazy
as
_
from
django_extensions.db.fields
import
AutoSlugField
...
...
@@ -436,6 +437,37 @@ class CourseRun(TimeStampedModel):
return
deadline
def
enrollable_seats
(
self
,
types
):
"""
Returns seats, of the given type(s), that can be enrolled in/purchased.
Arguments:
types (list of seat type names): Type of seats to limit the returned value to.
Returns:
List of Seats
"""
now
=
timezone
.
now
()
enrollable_seats
=
[]
if
self
.
start
and
self
.
start
>
now
:
return
enrollable_seats
if
self
.
end
and
now
>
self
.
end
:
return
enrollable_seats
if
self
.
enrollment_start
and
self
.
enrollment_start
>
now
:
return
enrollable_seats
if
self
.
enrollment_end
and
now
>
self
.
enrollment_end
:
return
enrollable_seats
for
seat
in
self
.
seats
.
all
():
if
seat
.
type
in
types
and
(
not
seat
.
upgrade_deadline
or
now
<
seat
.
upgrade_deadline
):
enrollable_seats
.
append
(
seat
)
return
enrollable_seats
@property
def
program_types
(
self
):
"""
...
...
@@ -729,12 +761,42 @@ class Program(TimeStampedModel):
help_text
=
_
(
'The description of credit redemption for courses in program'
),
blank
=
True
,
null
=
True
)
one_click_purchase_enabled
=
models
.
BooleanField
(
default
=
False
,
help_text
=
_
(
'Allow courses in this program to be purchased in a single transaction'
)
)
objects
=
ProgramQuerySet
.
as_manager
()
def
__str__
(
self
):
return
self
.
title
@property
def
is_program_eligible_for_one_click_purchase
(
self
):
"""
Checks if the program is eligible for one click purchase.
To pass the check the program must have one_click_purchase field enabled
and all its courses must contain only one course run and the remaining
not excluded course run must contain a purchasable seat.
"""
if
not
self
.
one_click_purchase_enabled
:
return
False
excluded_course_runs
=
set
(
self
.
excluded_course_runs
.
all
())
applicable_seat_types
=
[
seat_type
.
name
.
lower
()
for
seat_type
in
self
.
type
.
applicable_seat_types
.
all
()]
for
course
in
self
.
courses
.
all
():
course_runs
=
set
(
course
.
course_runs
.
all
())
-
excluded_course_runs
if
len
(
course_runs
)
!=
1
:
return
False
if
not
course_runs
.
pop
()
.
enrollable_seats
(
applicable_seat_types
):
return
False
return
True
@cached_property
def
_course_run_weeks_to_complete
(
self
):
return
[
course_run
.
weeks_to_complete
for
course_run
in
self
.
course_runs
...
...
course_discovery/apps/course_metadata/tests/test_admin.py
View file @
e0081ed0
...
...
@@ -13,9 +13,10 @@ from selenium.webdriver.support.wait import WebDriverWait
from
course_discovery.apps.core.models
import
Partner
from
course_discovery.apps.core.tests.factories
import
USER_PASSWORD
,
UserFactory
from
course_discovery.apps.core.tests.helpers
import
make_image_file
from
course_discovery.apps.course_metadata.admin
import
ProgramEligibilityFilter
from
course_discovery.apps.course_metadata.choices
import
ProgramStatus
from
course_discovery.apps.course_metadata.forms
import
ProgramAdminForm
from
course_discovery.apps.course_metadata.models
import
Program
,
ProgramType
from
course_discovery.apps.course_metadata.models
import
Program
,
ProgramType
,
Seat
,
SeatType
from
course_discovery.apps.course_metadata.tests
import
factories
...
...
@@ -286,8 +287,8 @@ class ProgramAdminFunctionalTests(LiveServerTestCase):
'field-credit_redemption_overview'
,
'field-video'
,
'field-weeks_to_complete'
,
'field-min_hours_effort_per_week'
,
'field-max_hours_effort_per_week'
,
'field-courses'
,
'field-order_courses_by_start_date'
,
'field-custom_course_runs_display'
,
'field-excluded_course_runs'
,
'field-authoring_organizations'
,
'field-credit_backing_organizations'
,
'field-
job_outlook_items
'
,
'field-expected_learning_items'
,
'field-authoring_organizations'
,
'field-credit_backing_organizations'
,
'field-
one_click_purchase_enabled
'
,
'field-
job_outlook_items'
,
'field-
expected_learning_items'
,
]
self
.
assertEqual
(
actual
,
expected
)
...
...
@@ -349,3 +350,55 @@ class ProgramAdminFunctionalTests(LiveServerTestCase):
self
.
program
=
Program
.
objects
.
get
(
pk
=
self
.
program
.
pk
)
self
.
assertEqual
(
self
.
program
.
title
,
title
)
self
.
assertEqual
(
self
.
program
.
subtitle
,
subtitle
)
class
ProgramEligibilityFilterTests
(
TestCase
):
""" Tests for Program Eligibility Filter class. """
parameter_name
=
'eligible_for_one_click_purchase'
def
test_queryset_method_returns_all_programs
(
self
):
""" Verify that all programs pass the filter. """
verified_seat_type
,
__
=
SeatType
.
objects
.
get_or_create
(
name
=
Seat
.
VERIFIED
)
program_type
=
factories
.
ProgramTypeFactory
(
applicable_seat_types
=
[
verified_seat_type
])
program_filter
=
ProgramEligibilityFilter
(
None
,
{},
None
,
None
)
course_run
=
factories
.
CourseRunFactory
()
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
'verified'
,
upgrade_deadline
=
None
)
one_click_purchase_eligible_program
=
factories
.
ProgramFactory
(
type
=
program_type
,
courses
=
[
course_run
.
course
],
one_click_purchase_enabled
=
True
)
one_click_purchase_ineligible_program
=
factories
.
ProgramFactory
(
courses
=
[
course_run
.
course
])
with
self
.
assertNumQueries
(
1
):
self
.
assertEqual
(
list
(
program_filter
.
queryset
({},
Program
.
objects
.
all
())),
[
one_click_purchase_ineligible_program
,
one_click_purchase_eligible_program
]
)
def
test_queryset_method_returns_eligible_programs
(
self
):
""" Verify that one click purchase eligible programs pass the filter. """
verified_seat_type
,
__
=
SeatType
.
objects
.
get_or_create
(
name
=
Seat
.
VERIFIED
)
program_type
=
factories
.
ProgramTypeFactory
(
applicable_seat_types
=
[
verified_seat_type
])
program_filter
=
ProgramEligibilityFilter
(
None
,
{
self
.
parameter_name
:
1
},
None
,
None
)
course_run
=
factories
.
CourseRunFactory
(
end
=
None
,
enrollment_end
=
None
,)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
'verified'
,
upgrade_deadline
=
None
)
one_click_purchase_eligible_program
=
factories
.
ProgramFactory
(
type
=
program_type
,
courses
=
[
course_run
.
course
],
one_click_purchase_enabled
=
True
,
)
with
self
.
assertNumQueries
(
10
):
self
.
assertEqual
(
list
(
program_filter
.
queryset
({},
Program
.
objects
.
all
())),
[
one_click_purchase_eligible_program
]
)
def
test_queryset_method_returns_ineligible_programs
(
self
):
""" Verify programs ineligible for one-click purchase do not pass the filter. """
program_filter
=
ProgramEligibilityFilter
(
None
,
{
self
.
parameter_name
:
0
},
None
,
None
)
one_click_purchase_ineligible_program
=
factories
.
ProgramFactory
(
one_click_purchase_enabled
=
False
)
with
self
.
assertNumQueries
(
4
):
self
.
assertEqual
(
list
(
program_filter
.
queryset
({},
Program
.
objects
.
all
())),
[
one_click_purchase_ineligible_program
]
)
course_discovery/apps/course_metadata/tests/test_models.py
View file @
e0081ed0
...
...
@@ -68,6 +68,17 @@ class CourseRunTests(TestCase):
super
(
CourseRunTests
,
self
)
.
setUp
()
self
.
course_run
=
factories
.
CourseRunFactory
()
def
test_enrollable_seats
(
self
):
""" Verify the expected seats get returned. """
course_run
=
factories
.
CourseRunFactory
(
start
=
None
,
end
=
None
,
enrollment_start
=
None
,
enrollment_end
=
None
)
verified_seat
=
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
Seat
.
VERIFIED
,
upgrade_deadline
=
None
)
professional_seat
=
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
Seat
.
PROFESSIONAL
,
upgrade_deadline
=
None
)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
Seat
.
HONOR
,
upgrade_deadline
=
None
)
self
.
assertEqual
(
course_run
.
enrollable_seats
([
Seat
.
VERIFIED
,
Seat
.
PROFESSIONAL
]),
[
verified_seat
,
professional_seat
]
)
def
test_str
(
self
):
""" Verify casting an instance to a string returns a string containing the key and title. """
course_run
=
self
.
course_run
...
...
@@ -405,6 +416,146 @@ class ProgramTests(MarketingSitePublisherTestMixin):
return
factories
.
ProgramFactory
(
type
=
program_type
,
courses
=
[
course_run
.
course
])
def
assert_one_click_purchase_ineligible_program
(
self
,
start
=
None
,
end
=
None
,
enrollment_start
=
None
,
enrollment_end
=
None
,
seat_type
=
Seat
.
VERIFIED
,
upgrade_deadline
=
None
,
one_click_purchase_enabled
=
True
,
excluded_course_runs
=
None
,
program_type
=
None
,):
course_run
=
factories
.
CourseRunFactory
(
start
=
start
,
end
=
end
,
enrollment_start
=
enrollment_start
,
enrollment_end
=
enrollment_end
)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
seat_type
,
upgrade_deadline
=
upgrade_deadline
)
program
=
factories
.
ProgramFactory
(
courses
=
[
course_run
.
course
],
excluded_course_runs
=
excluded_course_runs
,
one_click_purchase_enabled
=
one_click_purchase_enabled
,
type
=
program_type
,
)
self
.
assertFalse
(
program
.
is_program_eligible_for_one_click_purchase
)
def
test_one_click_purchase_eligible
(
self
):
""" Verify that program is one click purchase eligible. """
verified_seat_type
,
__
=
SeatType
.
objects
.
get_or_create
(
name
=
Seat
.
VERIFIED
)
program_type
=
factories
.
ProgramTypeFactory
(
applicable_seat_types
=
[
verified_seat_type
])
# Program has one_click_purchase_enabled set to True,
# all courses have one course run, all course runs have
# verified seat types
courses
=
[]
for
__
in
range
(
3
):
course_run
=
factories
.
CourseRunFactory
(
end
=
None
,
enrollment_end
=
None
)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
Seat
.
VERIFIED
,
upgrade_deadline
=
None
)
courses
.
append
(
course_run
.
course
)
program
=
factories
.
ProgramFactory
(
courses
=
courses
,
one_click_purchase_enabled
=
True
,
type
=
program_type
,
)
self
.
assertTrue
(
program
.
is_program_eligible_for_one_click_purchase
)
# Program has one_click_purchase_enabled set to True,
# course has all course runs excluded except one which
# has verified seat type
course_run
=
factories
.
CourseRunFactory
(
end
=
None
,
enrollment_end
=
None
)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
Seat
.
VERIFIED
,
upgrade_deadline
=
None
)
course
=
course_run
.
course
excluded_course_runs
=
[
factories
.
CourseRunFactory
(
course
=
course
),
factories
.
CourseRunFactory
(
course
=
course
)
]
program
=
factories
.
ProgramFactory
(
courses
=
[
course
],
excluded_course_runs
=
excluded_course_runs
,
one_click_purchase_enabled
=
True
,
type
=
program_type
,
)
self
.
assertTrue
(
program
.
is_program_eligible_for_one_click_purchase
)
def
test_one_click_purchase_ineligible
(
self
):
""" Verify that program is one click purchase ineligible. """
yesterday
=
datetime
.
datetime
.
now
()
-
datetime
.
timedelta
(
days
=
1
)
tomorrow
=
datetime
.
datetime
.
now
()
+
datetime
.
timedelta
(
days
=
1
)
verified_seat_type
,
__
=
SeatType
.
objects
.
get_or_create
(
name
=
Seat
.
VERIFIED
)
program_type
=
factories
.
ProgramTypeFactory
(
applicable_seat_types
=
[
verified_seat_type
])
# Program has one_click_purchase_enabled set to False and
# every course has one course run
self
.
assert_one_click_purchase_ineligible_program
(
one_click_purchase_enabled
=
False
,
program_type
=
program_type
,
)
# Program has one_click_purchase_enabled set to True and
# one course has two course runs
course_run
=
factories
.
CourseRunFactory
(
end
=
None
,
enrollment_end
=
None
)
factories
.
CourseRunFactory
(
end
=
None
,
enrollment_end
=
None
,
course
=
course_run
.
course
)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
'verified'
,
upgrade_deadline
=
None
)
program
=
factories
.
ProgramFactory
(
courses
=
[
course_run
.
course
],
one_click_purchase_enabled
=
True
,
type
=
program_type
,
)
self
.
assertFalse
(
program
.
is_program_eligible_for_one_click_purchase
)
# Program has one_click_purchase_enabled set to True and
# one course with one course run excluded from the program
course_run
=
factories
.
CourseRunFactory
(
end
=
None
,
enrollment_end
=
None
)
factories
.
SeatFactory
(
course_run
=
course_run
,
type
=
'verified'
,
upgrade_deadline
=
None
)
program
=
factories
.
ProgramFactory
(
courses
=
[
course_run
.
course
],
one_click_purchase_enabled
=
True
,
excluded_course_runs
=
[
course_run
],
type
=
program_type
,
)
self
.
assertFalse
(
program
.
is_program_eligible_for_one_click_purchase
)
# Program has one_click_purchase_enabled set to True, one course
# with one course run, course run start date not passed
self
.
assert_one_click_purchase_ineligible_program
(
start
=
tomorrow
,
program_type
=
program_type
,
)
# Program has one_click_purchase_enabled set to True, one course
# with one course run, course run end date passed
self
.
assert_one_click_purchase_ineligible_program
(
end
=
yesterday
,
program_type
=
program_type
,
)
# Program has one_click_purchase_enabled set to True, one course
# with one course run, course run enrollment start date not passed
self
.
assert_one_click_purchase_ineligible_program
(
enrollment_start
=
tomorrow
,
program_type
=
program_type
,
)
# Program has one_click_purchase_enabled set to True, one course
# with one course run, course run enrollment end date passed
self
.
assert_one_click_purchase_ineligible_program
(
enrollment_end
=
yesterday
,
program_type
=
program_type
,
)
# Program has one_click_purchase_enabled set to True, one course
# with one course run, seat upgrade deadline passed
self
.
assert_one_click_purchase_ineligible_program
(
upgrade_deadline
=
yesterday
,
program_type
=
program_type
,
)
# Program has one_click_purchase_enabled set to True, one course
# with one course run, seat type is not purchasable
self
.
assert_one_click_purchase_ineligible_program
(
seat_type
=
'incorrect'
,
program_type
=
program_type
,
)
def
test_str
(
self
):
"""Verify that a program is properly converted to a str."""
self
.
assertEqual
(
str
(
self
.
program
),
self
.
program
.
title
)
...
...
course_discovery/conf/locale/en/LC_MESSAGES/django.mo
View file @
e0081ed0
No preview for this file type
course_discovery/conf/locale/en/LC_MESSAGES/django.po
View file @
e0081ed0
...
...
@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-04-0
6 12:30+05
00\n"
"POT-Creation-Date: 2017-04-0
7 11:51+02
00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
#: apps/api/filters.py
#, python-brace-format
...
...
@@ -201,6 +201,19 @@ msgid "Partners"
msgstr ""
#: apps/course_metadata/admin.py
msgid "eligible for one-click purchase"
msgstr ""
#: apps/course_metadata/admin.py apps/publisher/forms.py
#: templates/publisher/course_run_detail/_preview_accept_popup.html
msgid "Yes"
msgstr ""
#: apps/course_metadata/admin.py apps/publisher/forms.py
msgid "No"
msgstr ""
#: apps/course_metadata/admin.py
msgid "Included course runs"
msgstr ""
...
...
@@ -422,6 +435,10 @@ msgstr ""
msgid "The description of credit redemption for courses in program"
msgstr ""
#: apps/course_metadata/models.py
msgid "Allow courses in this program to be purchased in a single transaction"
msgstr ""
#: apps/course_metadata/views.py
msgid "Change program excluded course runs"
msgstr ""
...
...
@@ -599,15 +616,6 @@ msgid "Instructor"
msgstr ""
#: apps/publisher/forms.py
#: templates/publisher/course_run_detail/_preview_accept_popup.html
msgid "Yes"
msgstr ""
#: apps/publisher/forms.py
msgid "No"
msgstr ""
#: apps/publisher/forms.py
msgid "Pacing"
msgstr ""
...
...
course_discovery/conf/locale/eo/LC_MESSAGES/django.mo
View file @
e0081ed0
No preview for this file type
course_discovery/conf/locale/eo/LC_MESSAGES/django.po
View file @
e0081ed0
...
...
@@ -7,14 +7,14 @@ msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2017-04-0
6 12:30+05
00\n"
"POT-Creation-Date: 2017-04-0
7 11:51+02
00\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
"Language-Team: LANGUAGE <LL@li.org>\n"
"Language: \n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Language: \n"
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
#: apps/api/filters.py
...
...
@@ -242,6 +242,19 @@ msgid "Partners"
msgstr "Pärtnérs Ⱡ'σяєм ιρѕυм ∂#"
#: apps/course_metadata/admin.py
msgid "eligible for one-click purchase"
msgstr "élïgïßlé för öné-çlïçk pürçhäsé Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢т#"
#: apps/course_metadata/admin.py apps/publisher/forms.py
#: templates/publisher/course_run_detail/_preview_accept_popup.html
msgid "Yes"
msgstr "Ýés Ⱡ'σяєм#"
#: apps/course_metadata/admin.py apps/publisher/forms.py
msgid "No"
msgstr "Nö Ⱡ'σя#"
#: apps/course_metadata/admin.py
msgid "Included course runs"
msgstr "Ìnçlüdéd çöürsé rüns Ⱡ'σяєм ιρѕυм ∂σłσя ѕιт αмєт, #"
...
...
@@ -531,6 +544,12 @@ msgstr ""
"Thé désçrïptïön öf çrédït rédémptïön för çöürsés ïn prögräm Ⱡ'σяєм ιρѕυм "
"∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя α#"
#: apps/course_metadata/models.py
msgid "Allow courses in this program to be purchased in a single transaction"
msgstr ""
"Àllöw çöürsés ïn thïs prögräm tö ßé pürçhäséd ïn ä sïnglé tränsäçtïön Ⱡ'σяєм"
" ιρѕυм ∂σłσя ѕιт αмєт, ¢σηѕє¢тєтυя #"
#: apps/course_metadata/views.py
msgid "Change program excluded course runs"
msgstr ""
...
...
@@ -727,15 +746,6 @@ msgid "Instructor"
msgstr "Ìnstrüçtör Ⱡ'σяєм ιρѕυм ∂σłσ#"
#: apps/publisher/forms.py
#: templates/publisher/course_run_detail/_preview_accept_popup.html
msgid "Yes"
msgstr "Ýés Ⱡ'σяєм#"
#: apps/publisher/forms.py
msgid "No"
msgstr "Nö Ⱡ'σя#"
#: apps/publisher/forms.py
msgid "Pacing"
msgstr "Päçïng Ⱡ'σяєм ιρѕυ#"
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment