Merge commit '129d3b793d97ea32e6f42b4ca1f33bb0860157e0' into production
BIN
app/assets/images/Adobe_PDF_file_icon_32x32.png
Normal file
After ![]() (image error) Size: 979 B |
BIN
app/assets/images/pages/sales/chat_icon.png
Normal file
After ![]() (image error) Size: 449 B |
BIN
app/assets/images/pages/sales/classroom1.png
Normal file
After ![]() (image error) Size: 119 KiB |
BIN
app/assets/images/pages/sales/classroom2.png
Normal file
After ![]() (image error) Size: 122 KiB |
BIN
app/assets/images/pages/sales/classroom3.png
Normal file
After ![]() (image error) Size: 116 KiB |
BIN
app/assets/images/pages/sales/classroom4.png
Normal file
After ![]() (image error) Size: 120 KiB |
BIN
app/assets/images/pages/sales/classroom5.png
Normal file
After ![]() (image error) Size: 144 KiB |
BIN
app/assets/images/pages/sales/classroom6.png
Normal file
After ![]() (image error) Size: 86 KiB |
BIN
app/assets/images/pages/sales/content_table.png
Normal file
After ![]() (image error) Size: 123 KiB |
BIN
app/assets/images/pages/sales/down_arrow.png
Normal file
After ![]() (image error) Size: 438 B |
BIN
app/assets/images/pages/sales/hero_background.png
Normal file
After ![]() (image error) Size: 663 KiB |
BIN
app/assets/images/pages/sales/quote1.png
Normal file
After ![]() (image error) Size: 26 KiB |
BIN
app/assets/images/pages/sales/quote2.png
Normal file
After ![]() (image error) Size: 26 KiB |
BIN
app/assets/images/pages/sales/screen1.png
Normal file
After ![]() (image error) Size: 75 KiB |
BIN
app/assets/images/pages/sales/screen2.png
Normal file
After ![]() (image error) Size: 37 KiB |
BIN
app/assets/images/twitter_icon.png
Normal file
After ![]() (image error) Size: 471 B |
8
app/collections/Products.coffee
Normal file
|
@ -0,0 +1,8 @@
|
|||
CocoCollection = require './CocoCollection'
|
||||
Product = require 'models/Product'
|
||||
|
||||
module.exports = class Products extends CocoCollection
|
||||
model: Product
|
||||
url: '/db/products'
|
||||
|
||||
getByName: (name) -> @findWhere { name: name }
|
|
@ -24,7 +24,6 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
'account/profile': go('EmployersView') # Show the not-recruiting-now screen
|
||||
'account/payments': go('account/PaymentsView')
|
||||
'account/subscription': go('account/SubscriptionView')
|
||||
'account/subscription/sale': go('account/SubscriptionSaleView')
|
||||
'account/invoices': go('account/InvoicesView')
|
||||
'account/prepaid': go('account/PrepaidView')
|
||||
|
||||
|
@ -126,6 +125,8 @@ module.exports = class CocoRouter extends Backbone.Router
|
|||
|
||||
'preview': go('HomeView')
|
||||
|
||||
'schools': go('SalesView')
|
||||
|
||||
'teachers': go('TeachersView')
|
||||
'teachers/freetrial': go('TeachersFreeTrialView')
|
||||
|
||||
|
|
|
@ -244,7 +244,7 @@ module.exports.getCoursePraise = getCoursePraise = ->
|
|||
]
|
||||
praise[_.random(0, praise.length - 1)]
|
||||
|
||||
module.exports.getPrepaidCodeAmount = getPrepaidCodeAmount = (price=999, users=0, months=0) ->
|
||||
module.exports.getPrepaidCodeAmount = getPrepaidCodeAmount = (price=0, users=0, months=0) ->
|
||||
return 0 unless users > 0 and months > 0
|
||||
total = price * users * months
|
||||
total
|
||||
|
|
|
@ -59,6 +59,7 @@ module.exports = class Simulator extends CocoClass
|
|||
success: (taskData) =>
|
||||
return if @destroyed
|
||||
unless taskData
|
||||
@retryDelayInSeconds = 10
|
||||
@trigger 'statusUpdate', "No games to simulate. Trying another game in #{@retryDelayInSeconds} seconds."
|
||||
@simulateAnotherTaskAfterDelay()
|
||||
return
|
||||
|
|
|
@ -4,7 +4,7 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
no_ie: "CodeCombat no funciona en Internet Explorer 8 o versions anteriors. Perdó!" # Warning that only shows up in IE8 and older
|
||||
no_mobile: "CodeCombat no ha estat dissenyat per dispositius mòbils i per tant no funcionarà!" # Warning that shows up on mobile devices
|
||||
play: "Jugar" # The big play button that opens up the campaign view.
|
||||
# play_campaign_version: "Play Campaign Version" # Shows up under big play button if you only play /courses
|
||||
play_campaign_version: "Juga a la versió campanya" # Shows up under big play button if you only play /courses
|
||||
old_browser: "Uh oh, el teu navegador és massa antic per fer funcionar CodeCombat. Perdó!" # Warning that shows up on really old Firefox/Chrome/Safari
|
||||
old_browser_suffix: "Pots probar-ho igualment, però el més segur és que no funcioni."
|
||||
ipad_browser: "Males notícies: CodeCombat no funciona en el navegador d'iPad. Bones notícies: la nostre aplicació d'iPad està esperant l'aprovació d'Apple."
|
||||
|
@ -12,17 +12,17 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
for_beginners: "Per a principiants"
|
||||
multiplayer: "Multijugador" # Not currently shown on home page
|
||||
for_developers: "Per a Desenvolupadors" # Not currently shown on home page.
|
||||
or_ipad: "O descarrèga'l per iPad"
|
||||
# hoc_class_code: "I Have a Class Code"
|
||||
# hoc_enter: "Enter"
|
||||
# hoc_title: "Hour of Code?"
|
||||
or_ipad: "O descarrega'l per iPad"
|
||||
hoc_class_code: "Tinc un codi de classe"
|
||||
hoc_enter: "Introduir"
|
||||
hoc_title: "Hora del codi?"
|
||||
|
||||
nav:
|
||||
play: "Nivells" # The top nav bar entry where players choose which levels to play
|
||||
community: "Comunitat"
|
||||
# courses: "Courses"
|
||||
courses: "Cursos"
|
||||
editor: "Editor"
|
||||
blog: "Blog"
|
||||
blog: "Bloc"
|
||||
forum: "Fòrum"
|
||||
account: "Compte"
|
||||
profile: "Perfil"
|
||||
|
@ -35,30 +35,30 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
about: "Sobre Nosaltres"
|
||||
contact: "Contacta"
|
||||
twitter_follow: "Segueix-nos"
|
||||
teachers: "Profesors"
|
||||
# careers: "Careers"
|
||||
teachers: "Professors"
|
||||
careers: "Professions"
|
||||
|
||||
modal:
|
||||
close: "Tancar"
|
||||
okay: "Okey"
|
||||
okay: "D'acord"
|
||||
|
||||
not_found:
|
||||
page_not_found: "Pagina no trobada"
|
||||
page_not_found: "Pàgina no trobada"
|
||||
|
||||
diplomat_suggestion:
|
||||
title: "Ajuda a traduir CodeCombat!" # This shows up when a player switches to a non-English language using the language selector.
|
||||
sub_heading: "Neccesitem les teves habilitats lingüístiques."
|
||||
pitch_body: "Hem desenvolupat CodeCombat en anglès, peró tenim jugadors per tot el món. Molts d'ells volen jugar en Català, però no parlen anglès, per tant si pots parlar ambdós llengües, siusplau considereu iniciar sesió per a ser Diplomàtic i ajudar a traduir la web de CodeCombat i tots els seus nivell en Català."
|
||||
pitch_body: "Hem desenvolupat CodeCombat en anglès, però tenim jugadors per tot el món. Molts d'ells volen jugar en Català, però no parlen anglès, per tant si pots parlar ambdues llengües, siusplau considereu iniciar sessió per a ser Diplomàtic i ajudar a traduir la web de CodeCombat i tots els seus nivells en Català."
|
||||
missing_translations: "Fins que puguem traduir-ho tot en català, ho veuràs en anglès quant no estigui en català."
|
||||
learn_more: "Aprèn més sobre ser un diplomàtic"
|
||||
subscribe_as_diplomat: "Subscriu-te com a diplomàtic"
|
||||
|
||||
play:
|
||||
play_as: "Jugar com" # Ladder page
|
||||
# compete: "Compete!" # Course details page
|
||||
spectate: "Spectate" # Ladder page
|
||||
players: "jugadors" # Hover over a level on /play
|
||||
hours_played: "hores de joc" # Hover over a level on /play
|
||||
compete: "Competir!" # Course details page
|
||||
spectate: "Espectador" # Ladder page
|
||||
players: "Jugadors" # Hover over a level on /play
|
||||
hours_played: "Hores jugades" # Hover over a level on /play
|
||||
items: "Objectes" # Tooltip on item shop button from /play
|
||||
unlock: "Desbloquejar" # For purchasing items and heroes
|
||||
confirm: "Confirmar"
|
||||
|
@ -71,31 +71,31 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
achievements: "Triomfs" # Tooltip on achievement list button from /play
|
||||
account: "Compte" # Tooltip on account button from /play
|
||||
settings: "Configuració" # Tooltip on settings button from /play
|
||||
# poll: "Poll" # Tooltip on poll button from /play
|
||||
poll: "Enquesta" # Tooltip on poll button from /play
|
||||
next: "Següent" # Go from choose hero to choose inventory before playing a level
|
||||
change_hero: "Canviar heroi" # Go back from choose inventory to choose hero
|
||||
buy_gems: "Comprar Gemes"
|
||||
subscription_required: "Subscripció necessària"
|
||||
anonymous: "Jugador anònim"
|
||||
level_difficulty: "Dificultat: "
|
||||
# play_classroom_version: "Play Classroom Version" # Choose a level in campaign version that you also can play in one of your courses
|
||||
play_classroom_version: "Juga a la versió de classe" # Choose a level in campaign version that you also can play in one of your courses
|
||||
campaign_beginner: "Campanya del principiant"
|
||||
awaiting_levels_adventurer_prefix: "Fem cinc nivells per setmana" # {change}
|
||||
awaiting_levels_adventurer: "Inicia sessió com aventurer"
|
||||
awaiting_levels_adventurer_suffix: "sigues el primer en jugar els nous nivells"
|
||||
awaiting_levels_adventurer: "Inicia sessió com a aventurer"
|
||||
awaiting_levels_adventurer_suffix: "Sigues el primer en jugar els nous nivells"
|
||||
adjust_volume: "Ajustar volum"
|
||||
campaign_multiplayer: "Arenes Multijugador"
|
||||
campaign_multiplayer_description: "... on programes cara a cara contra altres jugadors."
|
||||
# campaign_old_multiplayer: "(Deprecated) Old Multiplayer Arenas"
|
||||
# campaign_old_multiplayer_description: "Relics of a more civilized age. No simulations are run for these older, hero-less multiplayer arenas."
|
||||
campaign_old_multiplayer: "(Obsolet) Arenes multijugador antigues"
|
||||
campaign_old_multiplayer_description: "Relíquies d'una era més civilitzada. No hi ha simulacions per aquestes arenes multijugador antigues."
|
||||
|
||||
share_progress_modal:
|
||||
blurb: "Estàs progressant molt! Digues a algú quan n'has après amb CodeCombat." # {change}
|
||||
email_invalid: "Correu electrònic invalid."
|
||||
email_invalid: "Correu electrònic invàlid."
|
||||
form_blurb: "Escriu els seus emails a sota i els hi ensenyarem!"
|
||||
form_label: "Correu electrònic"
|
||||
placeholder: "adreça de correu electrònic"
|
||||
title: "Excelent feina, Aprenent"
|
||||
title: "Excel·lent feina, aprenent"
|
||||
|
||||
login:
|
||||
sign_up: "Crear un compte"
|
||||
|
@ -115,12 +115,12 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
creating: "Creant Compte..."
|
||||
sign_up: "Registrar-se"
|
||||
log_in: "Iniciar sessió amb la teva contrasenya"
|
||||
social_signup: "O, pots iniciar sessió desde Facebook o G+:"
|
||||
social_signup: "O pots iniciar sessió desde Facebook o G+:"
|
||||
required: "Neccesites iniciar sessió abans ."
|
||||
login_switch: "Ja tens un compte?"
|
||||
# school_name: "School Name and City"
|
||||
# optional: "optional"
|
||||
# school_name_placeholder: "Example High School, Springfield, IL"
|
||||
school_name: "Nom de l'institut i ciutat"
|
||||
optional: "opcional"
|
||||
school_name_placeholder: "Exemple: IES Mossèn Alcover, Manacor"
|
||||
|
||||
recover:
|
||||
recover_account_title: "Recuperar Compte"
|
||||
|
@ -156,7 +156,7 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
unwatch: "Amaga"
|
||||
submit_patch: "Enviar pegat"
|
||||
submit_changes: "Puja canvis"
|
||||
# save_changes: "Save Changes"
|
||||
save_changes: "Guarda canvis"
|
||||
|
||||
general:
|
||||
and: "i"
|
||||
|
@ -168,15 +168,15 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
accepted: "Acceptat"
|
||||
rejected: "Rebutjat"
|
||||
withdrawn: "Retirat"
|
||||
# accept: "Accept"
|
||||
# reject: "Reject"
|
||||
# withdraw: "Withdraw"
|
||||
accept: "Accepta"
|
||||
reject: "Refusa"
|
||||
withdraw: "Retira"
|
||||
submitter: "Remitent"
|
||||
submitted: "Presentat"
|
||||
commit_msg: "nissatge de Commir"
|
||||
commit_msg: "Enviar missatge"
|
||||
version_history: "Historial de versions"
|
||||
version_history_for: "Historial de versions per: "
|
||||
select_changes: "Seleciona dos canvis sota per veure les diferencies."
|
||||
select_changes: "Selecciona dos canvis de sota per veure les diferències."
|
||||
undo_prefix: "Desfer"
|
||||
undo_shortcut: "(Ctrl+Z)"
|
||||
redo_prefix: "Refés"
|
||||
|
@ -186,8 +186,8 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
results: "Resultats"
|
||||
description: "Descripció"
|
||||
or: "o"
|
||||
subject: "Subjecte"
|
||||
email: "Email"
|
||||
subject: "Tema"
|
||||
email: "Correu electrònic"
|
||||
password: "Contrasenya"
|
||||
message: "Missatge"
|
||||
code: "Codi"
|
||||
|
@ -205,7 +205,7 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
player: "Jugador"
|
||||
player_level: "Nivell" # Like player level 5, not like level: Dungeons of Kithgard
|
||||
warrior: "Guerrer"
|
||||
ranger: "Ranger"
|
||||
ranger: "Guardabosc"
|
||||
wizard: "Mag"
|
||||
|
||||
units:
|
||||
|
@ -225,22 +225,22 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
years: "anys"
|
||||
|
||||
play_level:
|
||||
# completed_level: "Completed Level:"
|
||||
# course: "Course:"
|
||||
completed_level: "Nivell completat:"
|
||||
course: "Curs:"
|
||||
done: "Fet"
|
||||
# next_level: "Next Level:"
|
||||
# next_game: "Next game"
|
||||
# show_menu: "Show game menu"
|
||||
next_level: "Següent nivell:"
|
||||
next_game: "Següent joc"
|
||||
show_menu: "Mostrar menú del joc"
|
||||
home: "Inici" # Not used any more, will be removed soon.
|
||||
level: "Nivell" # Like "Level: Dungeons of Kithgard"
|
||||
skip: "Ometre"
|
||||
game_menu: "Menu de joc"
|
||||
game_menu: "Menú de joc"
|
||||
guide: "Guia"
|
||||
restart: "Recomençar"
|
||||
restart: "Reiniciar"
|
||||
goals: "Objectius"
|
||||
goal: "Objectiu"
|
||||
running: "Executant..."
|
||||
success: "Exit!"
|
||||
success: "Èxit!"
|
||||
incomplete: "Incomplet"
|
||||
timed_out: "S'ha acabat el temps"
|
||||
failing: "Fallant"
|
||||
|
@ -250,88 +250,88 @@ module.exports = nativeDescription: "Català", englishDescription: "Catalan", tr
|
|||
control_bar_join_game: "Entrar al joc"
|
||||
reload: "Recarregar"
|
||||
reload_title: "Recarregar tot el codi?"
|
||||
reload_really: "Estàs segur que vos recarregar aquest nivell al principi?"
|
||||
reload_really: "Estàs segur que vols recarregar aquest nivell des del principi?"
|
||||
reload_confirm: "Recarregar tot"
|
||||
victory: "Victòria"
|
||||
victory_title_prefix: ""
|
||||
victory_title_suffix: " Complet"
|
||||
victory_sign_up: "Inicia sessió per a desar el progressos"
|
||||
victory_sign_up_poke: "Vols guardar el teu codi? Crea un compte gratuit!"
|
||||
victory_sign_up_poke: "Vols guardar el teu codi? Crea un compte gratuït!"
|
||||
victory_rate_the_level: "Valora el nivell: " # {change}
|
||||
victory_return_to_ladder: "Retorna a les Escales"
|
||||
victory_saving_progress: "Desa progrés"
|
||||
victory_go_home: "Tornar a l'inici"
|
||||
victory_review: "Diguens més!"
|
||||
# victory_review_placeholder: "How was the level?"
|
||||
victory_review: "Explica'ns més!"
|
||||
victory_review_placeholder: "Com ha anat el nivell?"
|
||||
victory_hour_of_code_done: "Has acabat?"
|
||||
victory_hour_of_code_done_yes: "Sí, He acabat amb la meva Hora de Codi™!"
|
||||
victory_hour_of_code_done_yes: "Sí, he acabat amb la meva Hora del Codi™!"
|
||||
victory_experience_gained: "XP Guanyada"
|
||||
victory_gems_gained: "Gemmes guanyades"
|
||||
# victory_new_item: "New Item"
|
||||
# victory_viking_code_school: "Holy smokes, that was a hard level you just beat! If you aren't already a software developer, you should be. You just got fast-tracked for acceptance with Viking Code School, where you can take your skills to the next level and become a professional web developer in 14 weeks."
|
||||
# victory_become_a_viking: "Become a Viking"
|
||||
victory_new_item: "Objecte nou"
|
||||
victory_viking_code_school: "Ostres! Aquest nivell era un nivell difícil de superar! Si no ets un programador, ho hauries de ser. Acabes d'aconseguir una acceptació per la via ràpida a l'Escola de Programació Vikinga, on pot millorar les teves habilitats fins al següent nivell i esdevenir un programador de webs professional en 14 setmanes."
|
||||
victory_become_a_viking: "Converteix-te en un víking"
|
||||
guide_title: "Guia"
|
||||
tome_cast_button_run: "Executar"
|
||||
tome_cast_button_running: "Executant"
|
||||
tome_cast_button_ran: "Executat"
|
||||
tome_submit_button: "Envia"
|
||||
tome_reload_method: "Recarrega el codi original code per aquest metòde" # Title text for individual method reload button.
|
||||
tome_reload_method: "Recarrega el codi original per aquest metòde" # Title text for individual method reload button.
|
||||
tome_select_method: "Selecciona un mètode"
|
||||
tome_see_all_methods: "Veure tots els mètodes que pots editar" # Title text for method list selector (shown when there are multiple programmable methods).
|
||||
tome_select_a_thang: "Selecciona Algú Per"
|
||||
tome_select_a_thang: "Selecciona algú Per"
|
||||
tome_available_spells: "Encanteris disponibles"
|
||||
tome_your_skills: "Les teves habilitats"
|
||||
tome_current_method: "Mètode actual"
|
||||
code_saved: "Codi Guardat"
|
||||
skip_tutorial: "Passar (esc)"
|
||||
skip_tutorial: "Ometre (esc)"
|
||||
keyboard_shortcuts: "Dreceres del teclat"
|
||||
loading_ready: "Preparat!"
|
||||
loading_start: "Comença el nivell"
|
||||
problem_alert_title: "Arregla el Teu Codi"
|
||||
time_current: "Ara:"
|
||||
time_total: "Maxim:"
|
||||
time_total: "Màxim:"
|
||||
time_goto: "Ves a:"
|
||||
# non_user_code_problem_title: "Unable to Load Level"
|
||||
# infinite_loop_title: "Infinite Loop Detected"
|
||||
# infinite_loop_description: "The initial code to build the world never finished running. It's probably either really slow or has an infinite loop. Or there might be a bug. You can either try running this code again or reset the code to the default state. If that doesn't fix it, please let us know."
|
||||
# check_dev_console: "You can also open the developer console to see what might be going wrong."
|
||||
# check_dev_console_link: "(instructions)"
|
||||
non_user_code_problem_title: "Impossible carregar el nivell"
|
||||
infinite_loop_title: "Detectat un bucle infinit"
|
||||
infinite_loop_description: "El codi inicial mai acaba d'executar-se. Probablement sigui molt lent o tingui un bucle infinit. O pot ser un error. Pots provar de tornar a executar el codi o reiniciar-lo al seu estat original. Si no es soluciona, si us plau, fes-nos-ho saber."
|
||||
check_dev_console: "També pots obrir la consola de desenvolupament per veure què surt malament."
|
||||
check_dev_console_link: "(instruccions)"
|
||||
infinite_loop_try_again: "Tornar a intentar"
|
||||
infinite_loop_reset_level: "Reiniciar nivell"
|
||||
infinite_loop_comment_out: "Descommenta el Meu Codi"
|
||||
infinite_loop_comment_out: "Treu els comentaris del meu codi"
|
||||
tip_toggle_play: "Canvia entre reproduir/pausa amb Ctrl+P"
|
||||
tip_scrub_shortcut: "Ctrl+[ i Ctrl+] per rebobinar i avançar" # {change}
|
||||
# tip_guide_exists: "Click the guide, inside game menu (at the top of the page), for useful info."
|
||||
tip_guide_exists: "Clica a la guia dins el menú del joc (a la part superior de la pàgina) per informació útil."
|
||||
tip_open_source: "CodeCombat és 100% codi lliure!"
|
||||
# tip_tell_friends: "Enjoying CodeCombat? Tell your friends about us!"
|
||||
tip_tell_friends: "Gaudint de CodeCombat? Explica'ls-ho als teus amics!"
|
||||
tip_beta_launch: "CodeCombat va llançar la seva beta l'octubre de 2013."
|
||||
tip_think_solution: "Pensa en la solució,no en el problema."
|
||||
tip_think_solution: "Pensa en la solució, no en el problema."
|
||||
tip_theory_practice: "En teoria no hi ha diferència entre la teoria i la pràctica. Però a la pràctica si que n'hi ha. - Yogi Berra"
|
||||
tip_error_free: "Només hi ha dues maneres d'escriure programes sense errors; la tercera és la única que funciona. - Alan Perlis"
|
||||
tip_debugging_program: "Si debuguejar és el procés d'eliminar errors, llavors programar és el procés de posar-los. - Edsger W. Dijkstra"
|
||||
# tip_forums: "Head over to the forums and tell us what you think!"
|
||||
tip_baby_coders: "En el futur fins i tot els bebés podran ser Artximags."
|
||||
# tip_morale_improves: "Loading will continue until morale improves."
|
||||
# tip_all_species: "We believe in equal opportunities to learn programming for all species."
|
||||
# tip_reticulating: "Reticulating spines."
|
||||
# tip_harry: "Yer a Wizard, "
|
||||
# tip_great_responsibility: "With great coding skill comes great debug responsibility."
|
||||
# tip_munchkin: "If you don't eat your vegetables, a munchkin will come after you while you're asleep."
|
||||
tip_binary: "Hi ha 10 tipus de persones al mon, les que saben programar en binari i les que no"
|
||||
# tip_commitment_yoda: "A programmer must have the deepest commitment, the most serious mind. ~ Yoda"
|
||||
# tip_no_try: "Do. Or do not. There is no try. - Yoda"
|
||||
# tip_patience: "Patience you must have, young Padawan. - Yoda"
|
||||
# tip_documented_bug: "A documented bug is not a bug; it is a feature."
|
||||
# tip_impossible: "It always seems impossible until it's done. - Nelson Mandela"
|
||||
# tip_talk_is_cheap: "Talk is cheap. Show me the code. - Linus Torvalds"
|
||||
# tip_first_language: "The most disastrous thing that you can ever learn is your first programming language. - Alan Kay"
|
||||
# tip_hardware_problem: "Q: How many programmers does it take to change a light bulb? A: None, it's a hardware problem."
|
||||
# tip_hofstadters_law: "Hofstadter's Law: It always takes longer than you expect, even when you take into account Hofstadter's Law."
|
||||
# tip_premature_optimization: "Premature optimization is the root of all evil. - Donald Knuth"
|
||||
# tip_brute_force: "When in doubt, use brute force. - Ken Thompson"
|
||||
# tip_extrapolation: "There are only two kinds of people: those that can extrapolate from incomplete data..."
|
||||
# tip_superpower: "Coding is the closest thing we have to a superpower."
|
||||
# tip_control_destiny: "In real open source, you have the right to control your own destiny. - Linus Torvalds"
|
||||
tip_debugging_program: "Si depurar és el procés per eliminar errors, llavors programar és el procés de posar-los. - Edsger W. Dijkstra"
|
||||
tip_forums: "Passa pels fòrums i digues el que penses!"
|
||||
tip_baby_coders: "En el futur fins i tot els nadons podran ser mags."
|
||||
tip_morale_improves: "La càrrega continuarà fins que la moral millori."
|
||||
tip_all_species: "Creiem en la igualtat d'oportunitats per aprendre a programar per a totes les espècies."
|
||||
tip_reticulating: "Reticulant punxes."
|
||||
tip_harry: "Ets un bruixot, "
|
||||
tip_great_responsibility: "Un gran coneixement del codi comporta una gran responsabilitat per a depurar-lo."
|
||||
tip_munchkin: "Si no menges les teves verdures, un munchkin vindrà mentre dormis."
|
||||
tip_binary: "Hi ha 10 tipus de persones al món, les que saben programar en binari i les que no"
|
||||
tip_commitment_yoda: "Un programador ha de tenir un compromís profund, una ment seriosa. ~ Yoda"
|
||||
tip_no_try: "Fes-ho. O no ho facis. Però no ho intentis. - Yoda"
|
||||
tip_patience: "Pacient has de ser, jove Padawan. - Yoda"
|
||||
tip_documented_bug: "Un error documentat no és un error; és un atractiu."
|
||||
tip_impossible: "Sempre sembla impossible fins que es fa. - Nelson Mandela"
|
||||
tip_talk_is_cheap: "Parlar és barat. Mostra'm el codi. - Linus Torvalds"
|
||||
tip_first_language: "La cosa més desastrosa que aprendràs mai és el teu primer llenguatge de programació. - Alan Kay"
|
||||
tip_hardware_problem: "P: Quants programadors són necessaris per canviar una bombeta? R: Cap, és un problema de hardware."
|
||||
tip_hofstadters_law: "Llei de Hofstadter: Sempre et portarà més feina del que esperaves, fins i tot tenint en compte la llei de Hofstadter."
|
||||
tip_premature_optimization: "La optimització prematura és l'arrel de la maldat. - Donald Knuth"
|
||||
tip_brute_force: "Quan dubtis, usa força bruta. - Ken Thompson"
|
||||
tip_extrapolation: "Hi ha dos tipus de persones: aquells que poden extrapolar des de dades incompletes..."
|
||||
tip_superpower: "Programar és el que més s'aproxima a un super poder."
|
||||
tip_control_destiny: "En un codi obert real tens el dret a controlar el teu propi destí. - Linus Torvalds"
|
||||
# tip_no_code: "No code is faster than no code."
|
||||
# tip_code_never_lies: "Code never lies, comments sometimes do. — Ron Jeffries"
|
||||
# tip_reusable_software: "Before software can be reusable it first has to be usable."
|
||||
|
|
|
@ -4,7 +4,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
no_ie: "Το CodeCombat δεν είναι συμβατό με το Internet Explorer 9 ή κάποια παλαιότερη έκδοση. Συγνώμη!" # Warning that only shows up in IE8 and older
|
||||
no_mobile: "Το CodeCombat δεν σχεδιάστηκε για κινητά και μπορεί να μην δουλεύει!" # Warning that shows up on mobile devices
|
||||
play: "Παίξε" # The big play button that opens up the campaign view.
|
||||
# play_campaign_version: "Play Campaign Version" # Shows up under big play button if you only play /courses
|
||||
play_campaign_version: "Παίξε σε Μορφή Εκστρατείας" # Shows up under big play button if you only play /courses
|
||||
old_browser: "Ωχ, ο περιηγητής σας είναι πολύ παλιός για να τρέξει το CodeCombat. Συγνώμη!" # Warning that shows up on really old Firefox/Chrome/Safari
|
||||
old_browser_suffix: "Μπορείτε να δοκιμάσετε, αλλά πιθανότατα να μην λειτουργήσει."
|
||||
ipad_browser: "Δυσάρεστα νέα: Το CodeCombat δεν τρέχει στο iPad μέσω περιηγητή. Ευχάριστα νέα: αναμένουμε την έγκριση της Apple για την εφαρμογή μας για iPad."
|
||||
|
@ -78,7 +78,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
subscription_required: "Απαιτείται εγγραφή"
|
||||
anonymous: "Ανώνυμοι Παίκτες"
|
||||
level_difficulty: "Δυσκολία: "
|
||||
# play_classroom_version: "Play Classroom Version" # Choose a level in campaign version that you also can play in one of your courses
|
||||
play_classroom_version: "Παίξε σε Μορφή Μαθημάτων" # Choose a level in campaign version that you also can play in one of your courses
|
||||
campaign_beginner: "Εκστρατεία για Αρχάριους"
|
||||
awaiting_levels_adventurer_prefix: "Έχουμε νέα επίπεδα κάθε εβδομάδα."
|
||||
awaiting_levels_adventurer: "Εγγραφή ως Adventurer"
|
||||
|
@ -118,9 +118,9 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
social_signup: "Ή, μπορείς να συνδεθείς μέσω Facebook ή G+:"
|
||||
required: "Θα πρέπει να συνδεθείτε πριν πάτε προς τα εκεί."
|
||||
login_switch: "Έχεις ήδη λογαριασμό;"
|
||||
# school_name: "School Name and City"
|
||||
# optional: "optional"
|
||||
# school_name_placeholder: "Example High School, Springfield, IL"
|
||||
school_name: "Ονομα Σχολείου και Πόλη"
|
||||
optional: "Προαιρετικό"
|
||||
school_name_placeholder: "Παράδειγμα ΕΠΑΛ Καλύμνου, Κάλυμνος"
|
||||
|
||||
recover:
|
||||
recover_account_title: "Ανάκτηση λογαριασμού"
|
||||
|
@ -249,7 +249,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
control_bar_multiplayer: "πολλαπλών παικτών"
|
||||
control_bar_join_game: "Παίξε κι εσύ"
|
||||
reload: "Επαναφόρτωση"
|
||||
reload_title: "Ανανέωση όλου του κωδικά;"
|
||||
reload_title: "Ανανέωση όλου του κώδικα;"
|
||||
reload_really: "Είσαι σίγουρος ότι θέλεις να φορτώσεις αυτό το επίπεδο από την αρχή;"
|
||||
reload_confirm: "Ανανέωση όλων"
|
||||
victory: "Νίκη"
|
||||
|
@ -855,7 +855,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
started_2: "Ξεκίνησε"
|
||||
not_started_2: "Δεν ξεκίνησε"
|
||||
view_solution: "Πάτα για να δεις τη λύση."
|
||||
# view_attempt: "Click to view attempt."
|
||||
view_attempt: "Κλικ για να δείς την προσπάθεια."
|
||||
latest_achievement: "Τελευταίο Επίτευγμα"
|
||||
playtime: "Χρόνος παιχνιδιού"
|
||||
last_played: "Έπαιξε τελευταία φορά"
|
||||
|
@ -877,7 +877,7 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
courses:
|
||||
course: "Μάθημα"
|
||||
courses: "μαθήματα"
|
||||
# create_new_class: "Create New Class"
|
||||
create_new_class: "Δημιουργια Νεας Ταξης"
|
||||
not_enrolled: "Δεν έχετε εγγραφεί στο μάθημα αυτό."
|
||||
visit_pref: "Παρακαλώ επισκεφτείτε τη "
|
||||
visit_suf: "σελίδα για να εγγραφείτε."
|
||||
|
@ -952,149 +952,148 @@ module.exports = nativeDescription: "Ελληνικά", englishDescription: "Gre
|
|||
topics: "Θέματα"
|
||||
hours_content: "Ώρες περιεχομένου:"
|
||||
get_free: "Πάρε ΔΩΡΕΑΝ μάθημα"
|
||||
# enroll_paid: "Enroll Students in Paid Courses"
|
||||
# you_have1: "You have"
|
||||
# you_have2: "unused paid enrollments"
|
||||
# use_one: "Use 1 paid enrollment for"
|
||||
# use_multiple: "Use paid enrollments for the following students:"
|
||||
# already_enrolled: "already enrolled"
|
||||
# licenses_remaining: "licenses remaining:"
|
||||
# insufficient_enrollments: "insufficient paid enrollments"
|
||||
# enroll_students: "Enroll Students"
|
||||
# get_enrollments: "Get More Enrollments"
|
||||
# change_language: "Change Course Language"
|
||||
# keep_using: "Keep Using"
|
||||
# switch_to: "Switch To"
|
||||
# greetings: "Greetings!"
|
||||
# learn_p: "Learn Python"
|
||||
# learn_j: "Learn JavaScript"
|
||||
# language_cannot_change: "Language cannot be changed once students join a class."
|
||||
# back_classrooms: "Back to my classrooms"
|
||||
# back_courses: "Back to my courses"
|
||||
# edit_details: "Edit class details"
|
||||
# enrolled_courses: "enrolled in paid courses:"
|
||||
# purchase_enrollments: "Purchase Enrollments"
|
||||
# remove_student: "remove student"
|
||||
# assign: "Assign"
|
||||
# to_assign: "to assign paid courses."
|
||||
# teacher: "Teacher"
|
||||
# complete: "Complete"
|
||||
# none: "None"
|
||||
# save: "Save"
|
||||
# play_campaign_title: "Play the Campaign"
|
||||
# play_campaign_description: "You’re ready to take the next step! Explore hundreds of challenging levels, learn advanced programming skills, and compete in multiplayer arenas!"
|
||||
# create_account_title: "Create an Account"
|
||||
# create_account_description: "Sign up for a FREE CodeCombat account and gain access to more levels, more programming skills, and more fun!"
|
||||
# preview_campaign_title: "Preview Campaign"
|
||||
# preview_campaign_description: "Take a sneak peek at all that CodeCombat has to offer before signing up for your FREE account."
|
||||
# arena: "Arena"
|
||||
# arena_soon_title: "Arena Coming Soon"
|
||||
# arena_soon_description: "We are working on a multiplayer arena for classrooms at the end of"
|
||||
# not_enrolled1: "Not enrolled"
|
||||
# not_enrolled2: "Ask your teacher to enroll you in the next course."
|
||||
# next_course: "Next Course"
|
||||
# coming_soon1: "Coming soon"
|
||||
# coming_soon2: "We are hard at work making more courses for you!"
|
||||
# available_levels: "Available Levels"
|
||||
# welcome_to_courses: "Adventurers, welcome to Courses!"
|
||||
# ready_to_play: "Ready to play?"
|
||||
# start_new_game: "Start New Game"
|
||||
# play_now_learn_header: "Play now to learn"
|
||||
# play_now_learn_1: "basic syntax to control your character"
|
||||
# play_now_learn_2: "while loops to solve pesky puzzles"
|
||||
# play_now_learn_3: "strings & variables to customize actions"
|
||||
# play_now_learn_4: "how to defeat an ogre (important life skills!)"
|
||||
# welcome_to_page: "Welcome to your Courses page!"
|
||||
# completed_hoc: "Amazing! You've completed the Hour of Code course!"
|
||||
# ready_for_more_header: "Ready for more? Play the campaign mode!"
|
||||
# ready_for_more_1: "Use gems to unlock new items!"
|
||||
# ready_for_more_2: "Play through brand new worlds and challenges"
|
||||
# ready_for_more_3: "Learn even more programming!"
|
||||
# saved_games: "Saved Games"
|
||||
# hoc: "Hour of Code"
|
||||
# my_classes: "My Classes"
|
||||
# class_added: "Class successfully added!"
|
||||
# view_class: "view class"
|
||||
# view_levels: "view levels"
|
||||
# join_class: "Join A Class"
|
||||
# ask_teacher_for_code: "Ask your teacher if you have a CodeCombat class code! If so, enter it below:"
|
||||
# enter_c_code: "<Enter Class Code>"
|
||||
# join: "Join"
|
||||
# joining: "Joining class"
|
||||
# course_complete: "Course Complete"
|
||||
# play_arena: "Play Arena"
|
||||
# start: "Start"
|
||||
# last_level: "Last Level"
|
||||
# welcome_to_hoc: "Adventurers, welcome to our Hour of Code!"
|
||||
# logged_in_as: "Logged in as:"
|
||||
# not_you: "Not you?"
|
||||
# welcome_back: "Hi adventurer, welcome back!"
|
||||
# continue_playing: "Continue Playing"
|
||||
# more_options: "More options:"
|
||||
# option1_header: "Option 1: Invite students via email"
|
||||
# option1_body: "Students will automatically be sent an invitation to join this class, and will need to create an account with a username and password."
|
||||
# option2_header: "Option 2: Send URL to your students"
|
||||
# option2_body: "Students will be asked to enter an email address, username and password to create an account."
|
||||
# option3_header: "Option 3: Direct students to codecombat.com/courses"
|
||||
# option3_body: "Give students the following passcode to enter along with an email address, username and password when they create an account."
|
||||
# thank_you_pref: "Thank you for your purchase! You can now assign"
|
||||
# thank_you_suff: "more students to paid courses."
|
||||
# return_to_class: "Return to classroom"
|
||||
# return_to_course_man: "Return to course management."
|
||||
# students_not_enrolled: "students not enrolled"
|
||||
# total_all_classes: "Total Across All Classes"
|
||||
# how_many_enrollments: "How many additional paid enrollments do you need?"
|
||||
# each_student_access: "Each student in a class will get access to Courses 2-4 once they are enrolled in paid courses. You may assign each course to each student individually."
|
||||
# purchase_now: "Purchase Now"
|
||||
# enrollments: "enrollments"
|
||||
# remove_student1: "Remove Student"
|
||||
# are_you_sure: "Are you sure you want to remove this student from this class?"
|
||||
# remove_description1: "Student will lose access to this classroom and assigned classes. Progress and gameplay is NOT lost, and the student can be added back to the classroom at any time."
|
||||
# remove_description2: "The activated paid license will not be returned."
|
||||
# keep_student: "Keep Student"
|
||||
# removing_user: "Removing user"
|
||||
# to_join_ask: "To join a class, ask your teacher for an unlock code."
|
||||
# join_this_class: "Join Class"
|
||||
# enter_here: "<enter unlock code here>"
|
||||
# successfully_joined: "Successfully joined"
|
||||
# click_to_start: "Click here to start taking"
|
||||
# my_courses: "My Courses"
|
||||
# classroom: "Classroom"
|
||||
# use_school_email: "use your school email if you have one"
|
||||
# unique_name: "a unique name no one has chosen"
|
||||
# pick_something: "pick something you can remember"
|
||||
# class_code: "Class Code"
|
||||
# optional_ask: "optional - ask your teacher to give you one!"
|
||||
# optional_school: "optional - what school do you go to?"
|
||||
# start_playing: "Start Playing"
|
||||
# skip_this: "Skip this, I'll create an account later!"
|
||||
# welcome: "Welcome"
|
||||
# getting_started: "Getting Started with Courses"
|
||||
# download_getting_started: "Download Getting Started Guide [PDF]"
|
||||
# getting_started_1: "Create a new class by clicking the green 'Create New Class' button below."
|
||||
# getting_started_2: "Once you've created a class, click the blue 'Add Students' button."
|
||||
# getting_started_3: "You'll see student's progress below as they sign up and join your class."
|
||||
# additional_resources: "Additional Resources"
|
||||
# additional_resources_1_pref: "Download/print our"
|
||||
# additional_resources_1_mid: "Course 1 Teacher's Guide"
|
||||
# additional_resources_1_suff: "explanations and solutions to each level."
|
||||
# additional_resources_2_pref: "Complete our"
|
||||
# additional_resources_2_suff: "to get 15 more hours of content for FREE for 2 months."
|
||||
# additional_resources_3_pref: "Visit our"
|
||||
# additional_resources_3_mid: "Teacher Forums"
|
||||
# additional_resources_3_suff: "to connect to fellow educators who are using CodeCombat."
|
||||
# your_classes: "Your Classes"
|
||||
# no_classes: "No classes yet!"
|
||||
# create_new_class1: "create new class"
|
||||
# available_courses: "Available Courses"
|
||||
# unused_enrollments: "Unused enrollments available:"
|
||||
# students_access: "All students get access to Introduction to Computer Science for free. One enrollment per student is required to assign them to paid CodeCombat courses. A single student does not need multiple enrollments to access all paid courses."
|
||||
# active_courses: "active courses"
|
||||
# no_students: "No students yet!"
|
||||
# add_students1: "add students"
|
||||
# view_edit: "view/edit"
|
||||
# students_enrolled: "students enrolled"
|
||||
# length: "Length:"
|
||||
enroll_paid: "Γράψε μαθητές σε μαθήματα με πληρωμή"
|
||||
you_have1: "Έχεις"
|
||||
you_have2: "αχρησιμοποιήτες πληρωμένες συνδρομές"
|
||||
use_one: "Χρησιμοποιήσε 1 πληρωμένη συνδρομή για"
|
||||
use_multiple: "Χρησιμοποιήσε τις πληρωμένη συνδρομές για τους παρακάτω μαθητές:"
|
||||
already_enrolled: "Ήδη εγγεγραμένος"
|
||||
licenses_remaining: "Συνδρομές που απομένουν:"
|
||||
insufficient_enrollments: "Δεν αρκούν οι πληρωμένες συνδρομές"
|
||||
enroll_students: " Γράψε Μαθητές"
|
||||
get_enrollments: "Ζήτα και αλλές εγγραφές"
|
||||
change_language: "Αλλαγή Γλώσσας Μαθήματος"
|
||||
keep_using: "Συνέχισε να χρησιμοποιείς"
|
||||
switch_to: "Αλλαγή σε"
|
||||
greetings: "Καλως ΄Ηρθες!"
|
||||
learn_p: "Μάθε Python"
|
||||
learn_j: "Μάθε JavaScript"
|
||||
language_cannot_change: "Η γλώσσα δεν μπορεί να αλλάξει από τη στιγμή που οι μαθητές θα συνδεθούν με την τάξη."
|
||||
back_classrooms: "Πίσω στις τάξεις μου"
|
||||
back_courses: "Πίσω στα μαθήματα μου"
|
||||
edit_details: "Επεξεργασία Ρυθμίσεων Τάξης"
|
||||
enrolled_courses: "Εγγεγραμμένοι σε μαθήματα με πληρωμή:"
|
||||
purchase_enrollments: "Αγόρασε Συνδρομές επί πληρωμή"
|
||||
remove_student: "Διαγραφή Μαθητή"
|
||||
assign: "Ανάθεση"
|
||||
to_assign: "Ανάθεση μαθημάτων επί πληρωμή."
|
||||
teacher: "Δάσκαλος"
|
||||
complete: "Ολοκληρωμένο"
|
||||
none: "Κανένα"
|
||||
save: "Αποθήκευση"
|
||||
play_campaign_title: "Παίξε την Εκστρατεία"
|
||||
play_campaign_description: "Είσαι έτοιμος να κάνει το επόμενο βήμα! Εξερευνήστε εκατοντάδες επίπεδα γεμάτα με νεές προκλήσεις, αποκτώνγτας προηγμένες γνώσεις προγραμματισμού, και ανταγωνιστείτε σε αρένες με άλλους παίκτες!"
|
||||
create_account_title: "Δημιουργία Λογαριασμού"
|
||||
create_account_description: "Εγγραφείτε για ένα Δωρέαν CodeCombat λογαριασμό και κερδίστε πρόσβαση σε περισσότερα επίπεδα και προγραμματιστικές τεχνικές και φυσικά περισσότερη διασκέδαση!"
|
||||
preview_campaign_title: "Προεπισκόπηση Εκστρατείας"
|
||||
preview_campaign_description: "Ρίξτε μια κλεφτή ματιά σε όλα όσα το CodeCombat έχει να προσφέρει πριν από την εγγραφή σας για το ΔΩΡΕΑΝ λογαριασμό."
|
||||
arena: "Αρενα"
|
||||
arena_soon_title: "Σύντομα Έρχεται Αρένα"
|
||||
arena_soon_description: "Κατασκευάζουμε μια αρένα πολλών παικτών για τάξεις στο τέλος του"
|
||||
not_enrolled1: "Όχι εγγεγραμμένος"
|
||||
not_enrolled2: "Ζήτα από το δάσκαλο σου να σε εγγράψει στο επόμενο μάθημα."
|
||||
next_course: "Επόμενο Μάθημα"
|
||||
coming_soon1: "Έρχεται Σύντομα"
|
||||
coming_soon2: "Εργαζόμαστε σκληρά, φτιάχνοντας νέα μαθήματα για εσάς!"
|
||||
available_levels: "Διαθέσιμα Επίπεδα"
|
||||
welcome_to_courses: " Εξερευνητές καλωσήρθατε στις Σειρές Μαθημάτων!"
|
||||
ready_to_play: "Έτοιμος να παίξεις?"
|
||||
start_new_game: " Ξεκίνα Νέο Παιχνίδι"
|
||||
play_now_learn_header: "Παίξε για να μάθεις"
|
||||
play_now_learn_1: "Βασικό συντακτικό για τον έλεγχο του ήρωα σου."
|
||||
play_now_learn_2: "Επαναληπτικοί Βρόχοι While για να λύνεις βαρετούς γρίφους"
|
||||
play_now_learn_3: "συμβολοσειρές και μεταβλητές για να τροποποιείς εύκολα τις ενέργειες σου"
|
||||
play_now_learn_4: " Πως να νικησεις ένα Ogre(απαραίτητο μάθημα επιβίωσης!)"
|
||||
welcome_to_page: "Καλως ήρθες στη σελίδα των μαθημάτων σου!"
|
||||
completed_hoc: "Καταπληκτικό! Ολοκλήρωσες την ώρα του κώδικα!"
|
||||
ready_for_more_header: "Έτοιμος για περισσότερα? Παίξε στις Εκστρατείες!"
|
||||
ready_for_more_1: "Χρησιμοποιήσε τα πετράδια για να ξεκλειδώσεις νέα αντικείμενα!"
|
||||
ready_for_more_2: "Παίξε σενέους κόσμους κυνηγώντας καινούριες προκλήσεις"
|
||||
ready_for_more_3: "Μάθε περισσότερα πάνω στο Προγραμματισμό!"
|
||||
saved_games: "Αποθηκευμένα Παιχνίδια"
|
||||
hoc: "Ώρα του Κώδικα"
|
||||
my_classes: "Οι Τάξεις μου"
|
||||
class_added: "Τάξη Προστέθηκε!"
|
||||
view_class: "Ελέγχος Τάξης"
|
||||
view_levels: "Ελέγχος Επίπεδων"
|
||||
join_class: "Σύνδεση με Τάξη"
|
||||
ask_teacher_for_code: "Ζήτα από το δάσκαλο σου, εάν έχει ένα κωδικό τάξης για το CodeCombat! Εάν έχει, πληκτρολόγησε το παρακάτω:"
|
||||
enter_c_code: "<Πληκτρολόγησε Κωδικό Τάξης>"
|
||||
join: "Σύνδεση"
|
||||
joining: "Σύνδεση με Τάξη"
|
||||
course_complete: "Μάθημα Ολοκληρωμένο"
|
||||
play_arena: "Παίξε στην Αρένα"
|
||||
start: "Εκκίνηση"
|
||||
last_level: "Προηγουμένο Επίπεδο"
|
||||
welcome_to_hoc: "Εξερευνητές, καλωσήρθατε στη δικιά μας Ώρα του Κώδικα!"
|
||||
logged_in_as: "Υπογράφεις ως:"
|
||||
not_you: "Δεν είσαι εσύ?"
|
||||
welcome_back: "Γειά σου εξερευνητή καλωσήρθες πίσω!"
|
||||
continue_playing: "Συνέχιση Παιχνιδιού"
|
||||
more_options: "Περισσότερες Επιλογές:"
|
||||
option1_header: "Επιλογή 1: Πρόσκληση στους μαθητές μέσω email"
|
||||
option1_body: "Οι μαθητές θα λάβουν αυτομάτα μια πρόσκληση να συνδεθούν με την τάξηε, θα χρειαστεί να δημιουργήσουν ένα λογαριασμό με όνομα χρήστη και κωδικό πρόσβασης."
|
||||
option2_header: "Επιλογή 2: Στείλε το URL στους μαθητές σου"
|
||||
option2_body: "Από τους μαθητές θα ζητηθεί να εισάγουν μια διεύθυνση email, καθώς και όνομα χρήστη με κωδικό πρόσβασης."
|
||||
option3_header: "Επιλογή 3: Καθοδήγησε τους μαθητές σου στο codecombat.com/courses"
|
||||
option3_body: "Δώσε στους μαθητές σου τον κωδικό που ακολουθεί για να το χρησιμοποιήσουν όταν θα δημιουργούν ένα λογαριασμό."
|
||||
thank_you_pref: "Ευχαριστούμε για την αγορά σου! Μπορείς τώρα να εκχωρήσεις"
|
||||
thank_you_suff: "και άλλους μαθητές στα μαθήματα επί πληρωμή."
|
||||
return_to_class: "Επιστροφή στην Τάξη"
|
||||
return_to_course_man: "Επιστροφή στη Διαχείριση Τάξης."
|
||||
students_not_enrolled: "μαθητές όχι εγγεγραμμένοι"
|
||||
total_all_classes: "Σύνολο σε όλες τις τάξεις"
|
||||
how_many_enrollments: "Πόσες ακόμα συνδρομές θα χρειαστείς?"
|
||||
each_student_access: " Κάθε μαθητής στην τάξη θα αποκτήσει πρόσβαση στα Μαθήματα 2-4 μόλις συνδεθούν με τα μαθήματα επί πληρωμή. Μπορείς να συνδέεις κάθε μάθημα με κάθε μαθητή ξεχωριστά."
|
||||
purchase_now: "Αγορά Τώρα"
|
||||
enrollments: "Συνδρομές"
|
||||
remove_student1: "Διαγραφή Μαθητή"
|
||||
are_you_sure: "Είσαι σίγουρος ότι θέλεις να διαγράψεις τον μαθητή από αυτή την τάξη?"
|
||||
remove_description1: "Ο μαθητής θα χάσει την πρόσβαση σε αυτή την τάξη και στα συνδεμένα μαθήματα. Η πρόοδος και το gameplay δεν θα χαθούν, και ο μαθητής μπορεί να προστεθεί πίσω στην τάξη, ανά πάσα στιγμή."
|
||||
remove_description2: "Η ενεργοποιημένη πληρωμένη συνδρομή δεν πρόκειται να επιστραφεί."
|
||||
keep_student: "Keep Student"
|
||||
removing_user: "Διαγραφή χρήστη"
|
||||
to_join_ask: "Για να συνδεθείς με μία τάξη, ζήτα από το δάσκαλο σου τον κώδικο τάξης."
|
||||
join_this_class: "Σύνδεση με Τάξη"
|
||||
enter_here: "<Πληκτρόλογησε κωδικό τάξης εδώ>"
|
||||
successfully_joined: "Επιτυχώς Συνδέθηκες"
|
||||
click_to_start: "Κλικ εδώ για να ξεκινήσεις"
|
||||
my_courses: "Μαθήματα μου"
|
||||
classroom: "Τάξη"
|
||||
use_school_email: "Χρησιμοποιήσε ένα email"
|
||||
unique_name: "Ένα όνομα μοναδικό"
|
||||
pick_something: "Διάλεξε κάτι που θα θυμάσαι"
|
||||
class_code: "Κωδικός Τάξης"
|
||||
optional_ask: "Προαιρετικό - ζήτα από το δάσκαλο σου να σου δώσει ένα!"
|
||||
optional_school: "Προαιρετικό - σε ποιό σχολείο πηγαίνεις?"
|
||||
start_playing: "Ξεκίνα να Παίζεις"
|
||||
skip_this: "Πάραλειψε τοs, θα δημιουργήσω λογαριασμό αργότερα!"
|
||||
welcome: "Καλώς Ήρθες"
|
||||
getting_started: "Ξεκινώντας με τις Σειρές Μαθημάτων"
|
||||
download_getting_started: "Κατέβασε Getting Started Guide [PDF]"
|
||||
getting_started_1: "Δημιούργησε μία νέα τάξη κάνοντας κλικ στο πράσινο κουμπί <Δημιουργία Τάξης> παρακάτω."
|
||||
getting_started_2: "Μόλις δημιουργήσετε την τάξη, κλικ στο μπλε κουμπί για να προσθέσετε μαθητές."
|
||||
getting_started_3: "Θα βλέπεις την πρόοδο των μαθητών σου μόλις ολοκληρώσουν την εγγραφή τους και συνδεθούν με την τάξη σου."
|
||||
additional_resources: "Additional Resources"
|
||||
additional_resources_1_pref: "Κατέβασε/Εκτύπωσε"
|
||||
additional_resources_1_mid: "Οδηγός Εκπαιδευτικού για Μάθημα 1"
|
||||
additional_resources_1_suff: "Επεξηγήσεις και λύσεις για το κάθε επίπεδο."
|
||||
additional_resources_2_pref: "Συμπλήρωσε την"
|
||||
additional_resources_2_suff: "για να κερδίσεις 15 ακόμα ώρες υλικού Δωρεάν για 2 μήνες."
|
||||
additional_resources_3_pref: "Επισκέψη"
|
||||
additional_resources_3_mid: "στα Forums των εκπαιδευτικών"
|
||||
additional_resources_3_suff: "για να επικοινωνήσεις με άλλους συναδέρφους που χρησιμοποιούν το CodeCombat."
|
||||
your_classes: "Οι Τάξεις σου"
|
||||
no_classes: "Όχι Τάξεις ακόμα!"
|
||||
create_new_class1: "δημιουργία Τάξης"
|
||||
available_courses: "Διαθέσιμα Μαθήματα"
|
||||
unused_enrollments: "Αδιάθετες συνδρομές:"
|
||||
students_access: "Όλοι οι μαθητές να έχουν πρόσβαση στην ενότητα Εισαγωγή στην Επιστήμη των Υπολογιστών δωρεάν. Μία συνδρομή ανά φοιτητή είναι υποχρεωτική για να να τους τοποθετήσετε στα μαθήματα που απαιτούν πληρωμή.Μία συνδρομή ανα μαθητή είναι αρκετή για την εγγραφή του σε όλα τα μαθήματα."
|
||||
no_students: "Όχι μαθητές ακόμα!"
|
||||
add_students1: "πρόσθεση μαθητών"
|
||||
view_edit: "Παρακολούθηση/Επεξεργασία"
|
||||
students_enrolled: "Εγγεγραμμένοι Μαθητές"
|
||||
length: "Μήκος:"
|
||||
|
||||
classes:
|
||||
archmage_title: "Αρχιμάγος"
|
||||
|
|
|
@ -438,11 +438,11 @@
|
|||
parents_title: "Dear Parent: Your child is learning to code. Will you help them continue?"
|
||||
parents_blurb1: "Your child has played __nLevels__ levels and learned programming basics. Help cultivate their interest and buy them a subscription so they can keep playing."
|
||||
parents_blurb1a: "Computer programming is an essential skill that your child will undoubtedly use as an adult. By 2020, basic software skills will be needed by 77% of jobs, and software engineers are in high demand across the world. Did you know that Computer Science is the highest-paid university degree?"
|
||||
parents_blurb2: "For $9.99 USD/mo, your child will get new challenges every week and personal email support from professional programmers."
|
||||
parents_blurb2a: "For ${{price}} USD/mo, your child will get new challenges every week and personal email support from professional programmers."
|
||||
parents_blurb3: "No Risk: 100% money back guarantee, easy 1-click unsubscribe."
|
||||
payment_methods: "Payment Methods"
|
||||
payment_methods_title: "Accepted Payment Methods"
|
||||
payment_methods_blurb1: "We currently accept credit cards and Alipay. You can also PayPal 29.97 USD to nick@codecombat.com with your account email in the memo to purchase three months' subscription and gems, or $99 for a year."
|
||||
payment_methods_blurb1a: "We currently accept credit cards and Alipay. You can also PayPal {{three_month_price}} USD to nick@codecombat.com with your account email in the memo to purchase three months' subscription and gems, or ${{year_price}} for a year."
|
||||
payment_methods_blurb2: "If you require an alternate form of payment, please contact"
|
||||
sale_already_subscribed: "You're already subscribed!"
|
||||
sale_blurb1: "Save $21"
|
||||
|
@ -461,7 +461,7 @@
|
|||
sale_title: "Back to School Sale"
|
||||
sale_view_button: "Buy 1 year subscription for"
|
||||
stripe_description: "Monthly Subscription"
|
||||
stripe_description_year_sale: "1 Year Subscription ($21 discount)"
|
||||
stripe_description_year_sale1: "1 Year Subscription (${{discount}} discount)"
|
||||
subscription_required_to_play: "You'll need a subscription to play this level."
|
||||
unlock_help_videos: "Subscribe to unlock all video tutorials."
|
||||
|
||||
|
@ -1569,7 +1569,7 @@
|
|||
email_settings_url: "your email settings"
|
||||
email_description_suffix: "or through links in the emails we send, you can change your preferences and easily unsubscribe at any time."
|
||||
cost_title: "Cost"
|
||||
cost_description: "CodeCombat is free to play for all of its core levels, with a $9.99 USD/mo subscription for access to extra level branches and 3500 bonus gems per month. You can cancel with a click, and we offer a 100% money-back guarantee."
|
||||
cost_description: "CodeCombat is free to play for all of its core levels, with a ${{price}} USD/mo subscription for access to extra level branches and {{gems}} bonus gems per month. You can cancel with a click, and we offer a 100% money-back guarantee."
|
||||
copyrights_title: "Copyrights and Licenses"
|
||||
contributor_title: "Contributor License Agreement"
|
||||
contributor_description_prefix: "All contributions, both on the site and on our GitHub repository, are subject to our"
|
||||
|
|
|
@ -14,8 +14,8 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
|
|||
for_developers: "Para Desarrolladores" # Not currently shown on home page.
|
||||
or_ipad: "O descargar para iPad"
|
||||
hoc_class_code: "Tengo un Código de Clase"
|
||||
# hoc_enter: "Enter"
|
||||
# hoc_title: "Hour of Code?"
|
||||
hoc_enter: "¿Entrar"
|
||||
hoc_title: " a la Hora de Código?"
|
||||
|
||||
nav:
|
||||
play: "Jugar" # The top nav bar entry where players choose which levels to play
|
||||
|
@ -619,9 +619,9 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
|
|||
cost_premium_server: "CodeCombat es gratis para lso primeros 5 niveles, después de ellos cuesta $9.99 USD mensuales para accesar a nuestros otros más de 190 niveles en nuestraos exclusivos servidores específicos para cada país."
|
||||
free_1: "Hay más de 110 niveles gratis que cubren cada concepto."
|
||||
free_2: "Una suscripción mensual le da acceso a tutoriales en vídeo y niveles extra para practicar."
|
||||
# free_3: "The CodeCombat content is divided into"
|
||||
free_3: "El contenido de CodeCombat está dividido en"
|
||||
free_4: "cursos"
|
||||
# free_5: ". The first course is free, and about an hour of material."
|
||||
free_5: ". El primer curso es gratis, y aproximadamente una hora de material."
|
||||
# free_6: "Access to the additional courses can be unlocked with a one-time purchase."
|
||||
teacher_subs_title: "¡Los amestros obtienen suscripciones gratuitas!" # {change}
|
||||
teacher_subs_0: "Ofrecemos suscripciones gratuitas a profesores con propósitos de evaluación." # {change}
|
||||
|
@ -676,14 +676,14 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
|
|||
approved_1: "Su aplicación a una suscripción gratuita fue" # {change}
|
||||
approved_2: "aprobada." # {change}
|
||||
# approved_4: "You can now enroll your students on the"
|
||||
# approved_5: "courses"
|
||||
approved_5: "cursos"
|
||||
# approved_6: "page."
|
||||
denied_1: "Su aplicación a una suscripción gratuita ha sido" # {change}
|
||||
denied_2: "denegada."
|
||||
contact_1: "Por favor contactarse"
|
||||
contact_2: "si tiene más preguntas."
|
||||
description_1: "Ofrecemos suscripciones gratuitas a maestros con propósitos de evaluación. Puede hallar más información en nuestra"
|
||||
# description_1b: "You can find more information on our"
|
||||
description_1b: "Puede hallar más información en nuestra"
|
||||
description_2: "página"
|
||||
description_3: "de maestros."
|
||||
description_4: "Por favor llene esta encuesta rápida y le mandaremos por email las instrucciones de configuración."
|
||||
|
@ -855,7 +855,7 @@ module.exports = nativeDescription: "Español (América Latina)", englishDescrip
|
|||
started_2: "Iniciado"
|
||||
not_started_2: "No inciiado"
|
||||
view_solution: "Click para ver la solución."
|
||||
# view_attempt: "Click to view attempt."
|
||||
view_attempt: "Click para ver intento."
|
||||
latest_achievement: "último logro"
|
||||
playtime: "Tiempo de juego"
|
||||
last_played: "Último jugado"
|
||||
|
|
6
app/models/Mandate.coffee
Normal file
|
@ -0,0 +1,6 @@
|
|||
CocoModel = require './CocoModel'
|
||||
|
||||
module.exports = class MandateModel extends CocoModel
|
||||
@className: 'Mandate'
|
||||
@schema: require 'schemas/models/mandate.schema'
|
||||
urlRoot: '/db/mandates'
|
6
app/models/Product.coffee
Normal file
|
@ -0,0 +1,6 @@
|
|||
CocoModel = require './CocoModel'
|
||||
|
||||
module.exports = class ProductModel extends CocoModel
|
||||
@className: 'Product'
|
||||
@schema: require 'schemas/models/product.schema'
|
||||
urlRoot: '/db/products'
|
18
app/schemas/models/mandate.schema.coffee
Normal file
|
@ -0,0 +1,18 @@
|
|||
c = require './../schemas'
|
||||
|
||||
module.exports = MandateSchema = {
|
||||
type: 'object'
|
||||
additionalProperties: false
|
||||
default:
|
||||
simulationThroughputRatio: 1
|
||||
properties: {
|
||||
simulationThroughputRatio:
|
||||
name: 'Simulation Throughput Ratio'
|
||||
description: '0-1 fraction of requests for a match to simulate that should be granted.'
|
||||
type: 'number'
|
||||
minimum: 0
|
||||
maximum: 1
|
||||
}
|
||||
}
|
||||
|
||||
c.extendBasicProperties MandateSchema, 'Mandate'
|
13
app/schemas/models/product.schema.coffee
Normal file
|
@ -0,0 +1,13 @@
|
|||
c = require './../schemas'
|
||||
|
||||
module.exports = ProductSchema = {
|
||||
type: 'object'
|
||||
additionalProperties: false
|
||||
properties: {
|
||||
name: { type: 'string' }
|
||||
amount: { type: 'integer', description: 'Cost in cents' }
|
||||
gems: { type: 'integer', description: 'Number of gems awarded' }
|
||||
}
|
||||
}
|
||||
|
||||
c.extendBasicProperties ProductSchema, 'Product'
|
|
@ -1,30 +0,0 @@
|
|||
#subscription-sale-view
|
||||
.above-blurb
|
||||
margin: 0 16% 0 16%
|
||||
.center
|
||||
text-align: center
|
||||
.feature-description
|
||||
font-size: 16px
|
||||
.sale-blurb
|
||||
font-size: 22px
|
||||
.sale-ends
|
||||
position: relative
|
||||
left: 0px
|
||||
top: 50px
|
||||
font-size: 18px
|
||||
line-height: 18px
|
||||
background-color: red
|
||||
color: white
|
||||
margin: 0 7px
|
||||
border-radius: 3px
|
||||
padding: 6px
|
||||
width: 200px
|
||||
text-align: center
|
||||
-ms-transform: rotate(330deg) /* IE 9 */
|
||||
-moz-transform: rotate(330deg) /* Firefox */
|
||||
-webkit-transform: rotate(330deg) /* Safari and Chrome */
|
||||
-o-transform: rotate(330deg) /* Opera */
|
||||
.sub-extended
|
||||
font-size: 12px
|
||||
#pay-button
|
||||
font-size: 18px
|
186
app/styles/sales-view.sass
Normal file
|
@ -0,0 +1,186 @@
|
|||
#sales-view
|
||||
|
||||
background-color: #F5F5F5
|
||||
font-family: Helvetica, sans-serif
|
||||
font-size: 15px
|
||||
line-height: 20px
|
||||
|
||||
// TODO: better way to remove content styling?
|
||||
#site-content-area
|
||||
width: 100%
|
||||
background-color: #F5F5F5
|
||||
border: none
|
||||
margin: auto
|
||||
padding: 0px
|
||||
min-height: inherit
|
||||
|
||||
.btn-contact-us
|
||||
background-color: #3878DE
|
||||
border: none
|
||||
color: #FFFFFF
|
||||
font-size: 18px
|
||||
margin-top: 20px
|
||||
padding: 20px
|
||||
width: 330px
|
||||
text-decoration: none
|
||||
text-transform: uppercase
|
||||
|
||||
div
|
||||
text-align: left
|
||||
|
||||
img
|
||||
float: left
|
||||
margin-right: 10px
|
||||
|
||||
|
||||
.btn-create-account, .btn-enter-courses
|
||||
background-color: #09AC48
|
||||
color: #FFFFFF
|
||||
display: inline-block
|
||||
font-size: 18px
|
||||
margin: 10px
|
||||
padding: 24px
|
||||
width: 400px
|
||||
text-decoration: none
|
||||
text-transform: uppercase
|
||||
|
||||
.btn-login-account
|
||||
color: #FFFFFF
|
||||
text-decoration: underline
|
||||
|
||||
.btn-setup-class
|
||||
margin-top: 20px
|
||||
text-transform: uppercase
|
||||
width: 300px
|
||||
|
||||
.section-header
|
||||
font-family: Merriweather
|
||||
font-size: 23px
|
||||
line-height: 29px
|
||||
padding: 0px 24px 0px 24px
|
||||
border-bottom: 1px solid lightgray
|
||||
|
||||
.section-subheader
|
||||
font-family: Helvetica, sans-serif
|
||||
font-size: 13px
|
||||
color: #727272
|
||||
line-height: 15px
|
||||
|
||||
.text-right
|
||||
text-align: right
|
||||
|
||||
#top-page-content
|
||||
background-image: url('/images/pages/sales/hero_background.png')
|
||||
background-size: cover
|
||||
color: #FFFFFF
|
||||
|
||||
.hero-quote-container
|
||||
margin: 20px
|
||||
width: 60%
|
||||
|
||||
.hero-quote
|
||||
font-family: Merriweather
|
||||
font-size: 30px
|
||||
font-weight: 700
|
||||
color: #FFFFFF
|
||||
line-height: 37px
|
||||
|
||||
.hero-quote-attribution
|
||||
font-family: Helvetica, sans-serif
|
||||
font-style: italic
|
||||
font-size: 13px
|
||||
color: #FFFFFF
|
||||
line-height: 16px
|
||||
margin-right: 100px
|
||||
text-align: right
|
||||
|
||||
#down-arrow
|
||||
padding: 20px
|
||||
|
||||
#main-content
|
||||
text-align: left
|
||||
display: inline-block
|
||||
width: 850px
|
||||
|
||||
#blurb1
|
||||
padding: 0px 20px 0px 20px
|
||||
|
||||
.blurb-subtitle
|
||||
font-size: 17px
|
||||
font-weight: bold
|
||||
|
||||
#course-comparisons
|
||||
font-size: 12px
|
||||
margin: 20px
|
||||
width: 90%
|
||||
|
||||
img
|
||||
width: 100%
|
||||
|
||||
.img-caption
|
||||
font-family: Helvetica, sans-serif
|
||||
font-style: italic
|
||||
font-size: 11px
|
||||
color: #727272
|
||||
line-height: 13px
|
||||
|
||||
.img-face
|
||||
background-color: #f0e5c7
|
||||
border-radius: 50%
|
||||
height: 100px
|
||||
width: 100px
|
||||
|
||||
.img-game
|
||||
width: 100%
|
||||
|
||||
.teacher-quote
|
||||
font-family: Merriweather
|
||||
font-weight: 300
|
||||
font-size: 18px
|
||||
line-height: 20px
|
||||
|
||||
.teacher-name
|
||||
font-family: Helvetica, sans-serif
|
||||
font-weight: 700
|
||||
font-size: 16px
|
||||
line-height: 19px
|
||||
|
||||
.teacher-location
|
||||
font-family: Helvetica, sans-serif
|
||||
font-style: italic
|
||||
font-size: 12px
|
||||
line-height: 14px
|
||||
|
||||
#quote1-container
|
||||
background-image: url('/images/pages/sales/quote1.png')
|
||||
background-repeat: no-repeat
|
||||
background-size: 100% auto
|
||||
height: 265px
|
||||
padding: 12px
|
||||
margin-right: 10px
|
||||
|
||||
.hero-quote-attribution
|
||||
margin-top: 60px
|
||||
|
||||
#quote2-container
|
||||
background-image: url('/images/pages/sales/quote2.png')
|
||||
background-repeat: no-repeat
|
||||
background-size: 100% auto
|
||||
height: 265px
|
||||
padding: 12px
|
||||
margin-left: 10px
|
||||
|
||||
.teacher-quote
|
||||
margin-top: 60px
|
||||
|
||||
.hero-quote-attribution
|
||||
margin-top: 20px
|
||||
|
||||
.twitter-attribution
|
||||
font-family: Helvetica
|
||||
font-weight: 700
|
||||
font-size: 11px
|
||||
line-height: 14px
|
||||
color: black
|
||||
display: inline-block
|
||||
text-decoration: none
|
|
@ -51,9 +51,9 @@ block content
|
|||
h2(data-i18n="nav.contact")
|
||||
| Contact
|
||||
p
|
||||
span CodeCombat, Inc.
|
||||
span CodeCombat Inc.
|
||||
br
|
||||
span 188 King St #507
|
||||
span 360 3rd St Suite 700 (Livefyre)
|
||||
br
|
||||
span San Francisco, CA 94107
|
||||
br
|
||||
|
|
|
@ -39,7 +39,7 @@ block content
|
|||
label.control-label.col-md-2(data-i18n="account_prepaid.purchase_total")
|
||||
.col-md-10
|
||||
p.form-control-static $
|
||||
span#total #{purchase.total.toFixed(2)}
|
||||
span#total #{(purchase.total/100).toFixed(2)}
|
||||
button#purchase-btn.btn.btn-success.pull-right(data-i18n="account_prepaid.purchase_button")
|
||||
.row
|
||||
.col-md-12
|
||||
|
@ -66,7 +66,7 @@ block content
|
|||
button#redeem-code-btn.btn.btn-success(data-i18n="account_prepaid.apply_account")
|
||||
.row
|
||||
.col-md-12
|
||||
.panel.panel-default
|
||||
#codes-panel.panel.panel-default
|
||||
.panel-heading
|
||||
.panel-title
|
||||
a(data-toggle="collapse" href="#codeslist")
|
||||
|
|
|
@ -1,76 +0,0 @@
|
|||
extends /templates/base
|
||||
|
||||
block content
|
||||
|
||||
ol.breadcrumb
|
||||
li
|
||||
a(href="/")
|
||||
span.glyphicon.glyphicon-home
|
||||
li
|
||||
a(href="/account", data-i18n="nav.account")
|
||||
li
|
||||
a(href="/account/subscription", data-i18n="account.subscription")
|
||||
li.active(data-i18n="account.sale") Sale
|
||||
|
||||
if hasSubscription
|
||||
h1(data-i18n="subscribe.sale_already_subscribed")
|
||||
span.spr(data-i18n="subscribe.sale_continue")
|
||||
a(href="/play", data-i18n="subscribe.sale_click_here")
|
||||
else
|
||||
if state === 'purchasing'
|
||||
.alert.alert-info(data-i18n="account_invoices.purchasing")
|
||||
else
|
||||
if view.onSale
|
||||
div.sale-ends
|
||||
if new Date() < saleEndDate
|
||||
span.spr(data-i18n="subscribe.sale_ends")
|
||||
span #{moment(saleEndDate).fromNow()}
|
||||
else
|
||||
span(data-i18n="subscribe.sale_limited_time")
|
||||
if view.onSale
|
||||
h1.center(data-i18n="subscribe.sale_title")
|
||||
p.center
|
||||
img(src="/images/pages/account/subscription/teacher-banner.png")
|
||||
br
|
||||
.above-blurb
|
||||
p.sale-blurb
|
||||
strong.spr(data-i18n="subscribe.sale_blurb1")
|
||||
span(data-i18n="subscribe.sale_blurb2")
|
||||
br
|
||||
div
|
||||
.sale-blurb(data-i18n="subscribe.sale_feature_here")
|
||||
ul
|
||||
li.feature-description(data-i18n="[html]subscribe.sale_feature2")
|
||||
li.feature-description(data-i18n="subscribe.feature3")
|
||||
li.feature-description(data-i18n="[html]subscribe.sale_feature4")
|
||||
li.feature-description(data-i18n="subscribe.feature5")
|
||||
li.feature-description(data-i18n="[html]subscribe.feature7")
|
||||
div.sub-extended(data-i18n="subscribe.sale_extended")
|
||||
br
|
||||
p.center
|
||||
button.btn.btn-success#pay-button #{payButtonText}
|
||||
table.above-blurb(cellpadding="8")
|
||||
tr
|
||||
td(colspan=2)
|
||||
h2.center(data-i18n="subscribe.sale_new_heroes")
|
||||
each hero in heroes
|
||||
if hero.get('extendedName') !== 'Captain Anya Weston' && hero.get('extendedName') !== 'Sir Tharin Thunderfist'
|
||||
tr
|
||||
td
|
||||
img(src="http://codecombat.com#{hero.getPortraitURL()}")
|
||||
td
|
||||
p.sale-blurb #{hero.name}
|
||||
p #{hero.class}
|
||||
p #{hero.description}
|
||||
br
|
||||
if state === 'declined'
|
||||
#declined-alert.alert.alert-danger.alert-dismissible
|
||||
span(data-i18n="account_invoices.declined")
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
span(aria-hidden="true") ×
|
||||
if state === 'unknown_error'
|
||||
#error-alert.alert.alert-danger.alert-dismissible
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
span(aria-hidden="true") ×
|
||||
p(data-i18n="loading_error.unknown")
|
||||
p= stateMessage
|
|
@ -133,54 +133,12 @@ block content
|
|||
.panel.panel-default
|
||||
.panel-heading
|
||||
h3(data-i18n="subscribe.managed_subs")
|
||||
p(data-i18n="subscribe.managed_subs_desc")
|
||||
p(data-i18n="subscribe.managed_subs_desc_2")
|
||||
h4(data-i18n="subscribe.group_discounts")
|
||||
table.table.table-striped.table-condensed.discount-table
|
||||
tr
|
||||
td(data-i18n="subscribe.group_discounts_1st")
|
||||
td(data-i18n="subscribe.group_discounts_full")
|
||||
tr
|
||||
td(data-i18n="subscribe.group_discounts_2nd")
|
||||
td(data-i18n="subscribe.group_discounts_20")
|
||||
tr
|
||||
td(data-i18n="subscribe.group_discounts_12th")
|
||||
td(data-i18n="subscribe.group_discounts_40")
|
||||
p
|
||||
span.spr Managed subscriptions are discontinued. Please contact
|
||||
a(href='mailto:team@codecombat.com') team@codecombat.com
|
||||
span.spl for more information.
|
||||
|
||||
.panel-body
|
||||
if view.recipientSubs.state === 'subscribing'
|
||||
.alert.alert-info(data-i18n="subscribe.subscribing")
|
||||
else
|
||||
if emailValidator.state === 'invalid'
|
||||
div.invalid-email-message(aria-hidden="true") please make sure all entries are valid emails
|
||||
textarea.recipient-emails(rows=3, data-i18n="[placeholder]subscribe.recipient_emails_placeholder")=emailValidator.lastEmails
|
||||
div
|
||||
button.recipients-subscribe-button.btn.btn-lg.btn-success(data-i18n="subscribe.subscribe_users")
|
||||
if view.recipientSubs.state === 'declined'
|
||||
br
|
||||
.alert.alert-danger.alert-dismissible
|
||||
span(data-i18n="buy_gems.declined")
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
span(aria-hidden="true") ×
|
||||
else if view.recipientSubs.state === 'unknown_error'
|
||||
br
|
||||
.alert.alert-danger.alert-dismissible
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
span(aria-hidden="true") ×
|
||||
p(data-i18n="loading_error.unknown")
|
||||
p= view.recipientSubs.stateMessage
|
||||
else if view.recipientSubs.justSubscribed && view.recipientSubs.justSubscribed.length > 0
|
||||
br
|
||||
.alert.alert-success.alert-dismissible
|
||||
if view.recipientSubs.justSubscribed.length > 0
|
||||
div(data-i18n="subscribe.users_subscribed")
|
||||
ul
|
||||
each email in view.recipientSubs.justSubscribed
|
||||
li= email
|
||||
else if view.recipientSubs.justSubscribed && view.recipientSubs.justSubscribed.length === 0
|
||||
br
|
||||
.alert.alert-success.alert-dismissible
|
||||
div(data-i18n="subscribe.no_users_subscribed")
|
||||
|
||||
if view.recipientSubs.nextPaymentAmount > 0 && view.recipientSubs.sponsorSub
|
||||
h4(data-i18n="account.next_payment")
|
||||
p= moment(new Date(view.recipientSubs.sponsorSub.current_period_end * 1000)).format('l')
|
||||
|
|
|
@ -23,9 +23,12 @@
|
|||
if !me.isOnPremiumServer()
|
||||
th.free-cell(data-i18n="subscribe.free")
|
||||
th
|
||||
//- TODO: find a better way to localize '$9.99/month'
|
||||
span $#{(view.product.amount / 100)}/
|
||||
span(data-i18n="subscribe.month")
|
||||
//- TODO: find a better way to localize price
|
||||
if view.basicProduct
|
||||
span $#{(view.basicProduct.get('amount') / 100)}/
|
||||
span(data-i18n="subscribe.month")
|
||||
else
|
||||
span '...'
|
||||
tbody
|
||||
tr
|
||||
td.feature-description
|
||||
|
|
|
@ -82,7 +82,7 @@ block content
|
|||
span(data-i18n="account_prepaid.purchase_total")
|
||||
span.spr : #{view.numberOfStudents}
|
||||
span(data-i18n="courses.enrollments")
|
||||
span.spl x $#{view.pricePerStudent.toFixed(2)} = #{view.getPriceString()}
|
||||
span.spl x $#{(view.pricePerStudent/100).toFixed(2)} = #{view.getPriceString()}
|
||||
|
||||
p.text-center
|
||||
button#purchase-btn.btn.btn-lg.btn-success.uppercase(data-i18n="courses.purchase_now")
|
||||
|
|
|
@ -52,7 +52,7 @@ block content
|
|||
if !me.isOnPremiumServer()
|
||||
h4(data-i18n="legal.cost_title")
|
||||
| Cost
|
||||
p(data-i18n="legal.cost_description")
|
||||
p#cost-description(data-i18n="legal.cost_description")
|
||||
| CodeCombat is free to play for all of its core levels, with a $9.99 USD/mo subscription for access to extra level branches and 3500 bonus gems per month. You can cancel with a click, and we offer a 100% money-back guarantee.
|
||||
|
||||
h2(data-i18n="legal.copyrights_title")
|
||||
|
|
|
@ -1,10 +1,10 @@
|
|||
.modal-dialog
|
||||
.modal-content
|
||||
|
||||
if state === 'purchasing'
|
||||
if view.state === 'purchasing'
|
||||
.alert.alert-info(data-i18n="buy_gems.purchasing")
|
||||
|
||||
else if state === 'retrying'
|
||||
else if view.state === 'retrying'
|
||||
#retrying-alert.alert.alert-danger(data-i18n="buy_gems.retrying")
|
||||
|
||||
else
|
||||
|
@ -12,12 +12,12 @@
|
|||
h1(data-i18n="play.buy_gems")
|
||||
|
||||
#products
|
||||
for product in products
|
||||
for product in view.products.models
|
||||
.product
|
||||
h4 x#{product.gems}
|
||||
h3(data-i18n=product.i18n)
|
||||
button.btn.btn-illustrated.btn-lg(value=product.id)
|
||||
span= product.price
|
||||
h4 x#{product.get('gems')}
|
||||
h3(data-i18n=product.get('i18n'))
|
||||
button.btn.btn-illustrated.btn-lg(value=product.get('name'))
|
||||
span= product.get('priceString')
|
||||
|
||||
.product
|
||||
h4(data-i18n="buy_gems.price") x3500 / mo
|
||||
|
@ -29,20 +29,20 @@
|
|||
else
|
||||
button.start-subscription-button.btn.btn-lg.btn-illustrated.btn-success(data-i18n="subscribe.subscribe_title") Subscribe
|
||||
|
||||
if state === 'declined'
|
||||
if view.state === 'declined'
|
||||
#declined-alert.alert.alert-danger.alert-dismissible
|
||||
span(data-i18n="buy_gems.declined")
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
span(aria-hidden="true") ×
|
||||
|
||||
if state === 'unknown_error'
|
||||
if view.state === 'unknown_error'
|
||||
#error-alert.alert.alert-danger.alert-dismissible
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
span(aria-hidden="true") ×
|
||||
p(data-i18n="loading_error.unknown")
|
||||
p= stateMessage
|
||||
p= view.stateMessage
|
||||
|
||||
if state === 'recovered_charge'
|
||||
if view.state === 'recovered_charge'
|
||||
#recovered-alert.alert.alert-danger.alert-dismissible
|
||||
span(data-i18n="buy_gems.recovered")
|
||||
button.close(type="button" data-dismiss="alert")
|
||||
|
|
212
app/templates/sales-view.jade
Normal file
|
@ -0,0 +1,212 @@
|
|||
extends /templates/base
|
||||
|
||||
//- Do NOT localize / i18n
|
||||
|
||||
block content
|
||||
#top-page-content
|
||||
br
|
||||
br
|
||||
.text-right
|
||||
button.btn-contact-us(href='/teachers/freetrial')
|
||||
img(src='/images/pages/sales/chat_icon.png')
|
||||
div contact us for pricing and a free trial
|
||||
|
||||
.hero-quote-container
|
||||
.hero-quote "CodeCombat is without question the most engaging platform for learning programming languages."
|
||||
.hero-quote-attribution Jonathan P., Elementary Computers Teacher
|
||||
|
||||
if me.isAnonymous()
|
||||
.text-center
|
||||
a.btn-create-account set up a free class
|
||||
.text-center
|
||||
span.spr Already have an account?
|
||||
a.btn-login-account Log in here.
|
||||
else
|
||||
.text-center
|
||||
a.btn-enter-courses(href="/courses/teachers") set up a free class
|
||||
|
||||
p.text-center
|
||||
a(href='#getting-started')
|
||||
img#down-arrow(src='/images/pages/sales/down_arrow.png')
|
||||
a(name="getting-started")
|
||||
|
||||
.text-center
|
||||
#main-content
|
||||
br
|
||||
p.text-center
|
||||
span.section-header What are CodeCombat Courses?
|
||||
p.text-center.section-subheader An entire semesters' worth of computer science curriculum for teachers who want to bring programming into their 4th-12th grade classes.
|
||||
br
|
||||
|
||||
.row
|
||||
.col-md-5
|
||||
img#img-game(src='/images/pages/sales/screen1.png')
|
||||
.text-center
|
||||
i
|
||||
small Students learn by writing code to complete levels in the game.
|
||||
.col-md-7
|
||||
#blurb1
|
||||
//- TODO: why don't jade inline tags work here?
|
||||
//- http://stackoverflow.com/questions/10953326/what-is-a-concise-way-to-create-inline-elements-in-jade
|
||||
p
|
||||
strong.spr CodeCombat
|
||||
span.spr is a platform for students to learn programming all while playing a game with their classmates. We believe in encouraging
|
||||
strong.spr real, typed code
|
||||
span to support healthy learning curve with programming.
|
||||
p
|
||||
span.spr CodeCombat's Courses consist of levels that have been specifically playtested to work best in a classroom setting, designed to be used by teachers with
|
||||
strong.spr no prior coding experience necessary.
|
||||
span Current Courses are available in JavaScript and Python, with solution guides provided for both.
|
||||
br
|
||||
br
|
||||
|
||||
.row
|
||||
.col-md-7
|
||||
#blurb2
|
||||
p.text-center.blurb-subtitle Designed with Teachers in Mind
|
||||
ul
|
||||
li Intuitive dashboard to track student progress
|
||||
li Course-specific teacher guides with full solutions to each levels
|
||||
li Teachers' forum and community-generated lesson plans.
|
||||
li Optional leaderboards to encourage friendly competitions
|
||||
li
|
||||
span.spr Auto-generate student progress reports
|
||||
i (coming soon!)
|
||||
li
|
||||
span.spr Multiple administrative accounts
|
||||
i (coming soon!)
|
||||
.col-md-5
|
||||
img.img-game(src='/images/pages/sales/screen2.png')
|
||||
.text-center
|
||||
i
|
||||
small Teachers can monitor progress, manage classrooms and more.
|
||||
|
||||
if me.isAnonymous()
|
||||
br
|
||||
.text-center
|
||||
a.btn-create-account set up a free class
|
||||
br
|
||||
br
|
||||
|
||||
p.text-center
|
||||
span.section-header Students (and parents) love us!
|
||||
br
|
||||
|
||||
table
|
||||
tr
|
||||
td
|
||||
#quote1-container
|
||||
.teacher-quote
|
||||
span.spr "My class had been struggling with the basics of Python all year. Today they were having fun and getting into it
|
||||
strong - I think they actually forgot that they were actually learning something."
|
||||
.row
|
||||
.col-md-4
|
||||
.col-md-8
|
||||
.hero-quote-attribution
|
||||
.teacher-name Tim M.
|
||||
.teacher-location Director of Technology, Tilton School
|
||||
td
|
||||
#quote2-container
|
||||
.row
|
||||
.col-md-8
|
||||
.hero-quote-attribution
|
||||
.teacher-name.text-right Darlease M.
|
||||
.teacher-location.text-right Technology Coordinator,
|
||||
.teacher-location.text-right Global Learning Charter Public School
|
||||
.col-md-4
|
||||
.teacher-quote
|
||||
span.spr "My girls, who were apprehensive about taking a coding class, ar some of my top students.
|
||||
strong They work together and explain the code to each other to make sure each understands."
|
||||
br
|
||||
|
||||
.text-center.section-subheader Students play CodeCombat during #HourOfCode 2015
|
||||
table(cellpadding=4)
|
||||
tr
|
||||
td
|
||||
img(src='/images/pages/sales/classroom3.png')
|
||||
.text-right
|
||||
a(href='https://twitter.com/flinng/status/674238468747354112')
|
||||
img(src='/images/twitter_icon.png')
|
||||
span.twitter-attribution @flinng
|
||||
td
|
||||
img(src='/images/pages/sales/classroom4.png')
|
||||
.text-right
|
||||
a(href='https://twitter.com/HikariKishi/status/674359511566577664')
|
||||
img(src='/images/twitter_icon.png')
|
||||
span.twitter-attribution @HikariKishi
|
||||
td
|
||||
img(src='/images/pages/sales/classroom2.png')
|
||||
.text-right
|
||||
a(href='https://twitter.com/Coderdojovno/status/675743290461941760')
|
||||
img(src='/images/twitter_icon.png')
|
||||
span.twitter-attribution @Coderdojovno
|
||||
table(cellpadding=4)
|
||||
tr
|
||||
td
|
||||
img(src='/images/pages/sales/classroom6.png')
|
||||
.text-right
|
||||
a(href='https://twitter.com/teachercoulter/status/674734565487828992')
|
||||
img(src='/images/twitter_icon.png')
|
||||
span.twitter-attribution @teachercoulter
|
||||
td
|
||||
img(src='/images/pages/sales/classroom1.png')
|
||||
.text-right
|
||||
a(href='https://twitter.com/CentreHigh/status/674643613360324608')
|
||||
img(src='/images/twitter_icon.png')
|
||||
span.twitter-attribution @CentreHigh
|
||||
td
|
||||
img(src='/images/pages/sales/classroom5.png')
|
||||
.text-right
|
||||
a(href='https://twitter.com/MrsYassen_GRE/status/674747949902090244')
|
||||
img(src='/images/twitter_icon.png')
|
||||
span.twitter-attribution @MrsYassen_GRE
|
||||
br
|
||||
|
||||
p.blurb-subtitle Facts about CodeCombat:
|
||||
.row
|
||||
.col-md-6
|
||||
ul
|
||||
li Students collaborate and help each other solve levels.
|
||||
li Appeals to all genders and a wide range of age groups.
|
||||
.cold-md-6
|
||||
ul
|
||||
li Typed code gives students an advantage over block-based programs.
|
||||
li Success with both high-performing and low-performing students, as well as ESL.
|
||||
br
|
||||
|
||||
.row
|
||||
.col-md-8
|
||||
p.text-center
|
||||
span.section-header What are paid courses?
|
||||
p The one-hour long "Introduction to Computer Science" course will always be free for an unlimited number of students. Paid enrollments allow each student access to Computer Science 2, 3, and 4, which is an additional 15 hours of content on top of the free contnet. Paid enrollments never expire.
|
||||
|
||||
#course-comparisons
|
||||
img(src='/images/pages/sales/content_table.png')
|
||||
br
|
||||
|
||||
p Per-student pricing allows us to better support flexibility for both large and small schools. Contact us if you are interested in purchasing paid course enrollments for your classroom or school. Free trials are also available upon request.
|
||||
|
||||
.col-md-4
|
||||
.well
|
||||
p.text-center.blurb-subtitle Resources for Teachers
|
||||
p
|
||||
a(href='http://codecombat.com/docs/CodeCombatHourofCodeGettingStartedGuide.pdf')
|
||||
img(src='/images/Adobe_PDF_file_icon_32x32.png')
|
||||
span Getting Started Guide
|
||||
p
|
||||
a(href='http://codecombat.com/docs/CodeCombatTeacherGuideCourse1.pdf')
|
||||
img(style='float:left;', src='/images/Adobe_PDF_file_icon_32x32.png')
|
||||
span Introduction to Computer Science Teacher's Guide
|
||||
br
|
||||
p
|
||||
i
|
||||
small Solution guides and additional lesson plans available for paid courses.
|
||||
p
|
||||
i
|
||||
small Contact team@codecombat.com with additional requests.
|
||||
br
|
||||
br
|
||||
|
||||
p.text-center
|
||||
button.btn-contact-us contact us for a free trial
|
||||
br
|
|
@ -14,7 +14,7 @@ module.exports = class HomeView extends RootView
|
|||
if @getQueryVariable 'hour_of_code'
|
||||
application.router.navigate "/hoc", trigger: true
|
||||
|
||||
isHourOfCodeWeek = true # Temporary: default to /hoc flow during the main event week
|
||||
isHourOfCodeWeek = false # Temporary: default to /hoc flow during the main event week
|
||||
if isHourOfCodeWeek and (@isNewPlayer() or (@justPlaysCourses() and me.isAnonymous()))
|
||||
# Go/return straight to playing single-player HoC course on Play click
|
||||
@playURL = '/hoc?go=true'
|
||||
|
|
|
@ -1,6 +1,26 @@
|
|||
RootView = require 'views/core/RootView'
|
||||
template = require 'templates/legal'
|
||||
Products = require 'collections/Products'
|
||||
|
||||
module.exports = class LegalView extends RootView
|
||||
id: 'legal-view'
|
||||
template: template
|
||||
|
||||
initialize: ->
|
||||
@products = new Products()
|
||||
@supermodel.loadCollection(@products, 'products')
|
||||
|
||||
onLoaded: ->
|
||||
basicSub = @products.findWhere({name: 'basic_subscription'})
|
||||
@price = (basicSub.get('amount') / 100).toFixed(2)
|
||||
@gems = basicSub.get('gems')
|
||||
super()
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
# TODO: Figure out how to use i18n interpolation in this case
|
||||
$el = @$('#cost-description')
|
||||
f = =>
|
||||
$el.text($el.text().replace('{{price}}', @price))
|
||||
$el.text($el.text().replace('{{gems}}', @gems))
|
||||
_.defer(f) # i18n call gets made immediately after render
|
||||
|
|
27
app/views/SalesView.coffee
Normal file
|
@ -0,0 +1,27 @@
|
|||
app = require 'core/application'
|
||||
AuthModal = require 'views/core/AuthModal'
|
||||
RootView = require 'views/core/RootView'
|
||||
template = require 'templates/sales-view'
|
||||
|
||||
module.exports = class SalesView extends RootView
|
||||
id: 'sales-view'
|
||||
template: template
|
||||
|
||||
events:
|
||||
'click .btn-contact-us': 'onClickContactUs'
|
||||
'click .btn-create-account': 'onClickSignup'
|
||||
'click .btn-login-account': 'onClickLogin'
|
||||
|
||||
getTitle: ->
|
||||
'CodeCombat'
|
||||
|
||||
onClickContactUs: (e) ->
|
||||
app.router.navigate '/teachers/freetrial', trigger: true
|
||||
|
||||
onClickLogin: (e) ->
|
||||
@openModalView new AuthModal(mode: 'login') if me.get('anonymous')
|
||||
window.tracker?.trackEvent 'Started Login', category: 'Sales', label: 'Sales Login'
|
||||
|
||||
onClickSignup: (e) ->
|
||||
@openModalView new AuthModal() if me.get('anonymous')
|
||||
window.tracker?.trackEvent 'Started Signup', category: 'Sales', label: 'Sales Create'
|
|
@ -7,6 +7,7 @@ Prepaid = require '../../models/Prepaid'
|
|||
utils = require 'core/utils'
|
||||
RedeemModal = require 'views/account/PrepaidRedeemModal'
|
||||
forms = require 'core/forms'
|
||||
Products = require 'collections/Products'
|
||||
|
||||
# TODO: remove redeem code modal
|
||||
|
||||
|
@ -26,12 +27,10 @@ module.exports = class PrepaidView extends RootView
|
|||
subscriptions:
|
||||
'stripe:received-token': 'onStripeReceivedToken'
|
||||
|
||||
baseAmount: 9.99
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
@purchase =
|
||||
total: @baseAmount
|
||||
total: 0
|
||||
users: 3
|
||||
months: 3
|
||||
@updateTotal()
|
||||
|
@ -45,6 +44,14 @@ module.exports = class PrepaidView extends RootView
|
|||
@ppcQuery = true
|
||||
@loadPrepaid(@ppc)
|
||||
|
||||
@products = new Products()
|
||||
@supermodel.loadCollection(@products, 'products')
|
||||
|
||||
onLoaded: ->
|
||||
@prepaidProduct = @products.findWhere { name: 'prepaid_subscription' }
|
||||
@updateTotal()
|
||||
super()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.purchase = @purchase
|
||||
|
@ -62,7 +69,8 @@ module.exports = class PrepaidView extends RootView
|
|||
noty text: message, layout: 'topCenter', type: type, killer: false, timeout: 5000, dismissQueue: true, maxVisible: 3
|
||||
|
||||
updateTotal: ->
|
||||
@purchase.total = getPrepaidCodeAmount(@baseAmount, @purchase.users, @purchase.months)
|
||||
return unless @prepaidProduct
|
||||
@purchase.total = getPrepaidCodeAmount(@prepaidProduct.get('amount'), @purchase.users, @purchase.months)
|
||||
@renderSelectors("#total", "#users-input", "#months-input")
|
||||
|
||||
# Form Input Callbacks
|
||||
|
@ -99,7 +107,7 @@ module.exports = class PrepaidView extends RootView
|
|||
onClickPurchaseButton: (e) ->
|
||||
return unless $("#users-input").val() >= 3 or $("#months-input").val() >= 3
|
||||
@purchaseTimestamp = new Date().getTime()
|
||||
@stripeAmount = @purchase.total * 100
|
||||
@stripeAmount = @purchase.total
|
||||
@description = "Prepaid Code for " + @purchase.users + " users / " + @purchase.months + " months"
|
||||
|
||||
stripeHandler.open
|
||||
|
@ -179,6 +187,7 @@ module.exports = class PrepaidView extends RootView
|
|||
# console.log 'SUCCESS: Prepaid purchase', model.code
|
||||
@statusMessage "Successfully purchased Prepaid Code!", "success"
|
||||
@codes.add(model)
|
||||
@renderSelectors('#codes-panel')
|
||||
|
||||
@statusMessage "Finalizing purchase...", "information"
|
||||
@supermodel.addRequestResource('purchase_prepaid', options, 0).load()
|
||||
|
|
|
@ -1,92 +0,0 @@
|
|||
RootView = require 'views/core/RootView'
|
||||
template = require 'templates/account/subscription-sale-view'
|
||||
app = require 'core/application'
|
||||
AuthModal = require 'views/core/AuthModal'
|
||||
CocoCollection = require 'collections/CocoCollection'
|
||||
stripeHandler = require 'core/services/stripe'
|
||||
ThangType = require 'models/ThangType'
|
||||
utils = require 'core/utils'
|
||||
|
||||
module.exports = class SubscriptionSaleView extends RootView
|
||||
id: "subscription-sale-view"
|
||||
template: template
|
||||
yearSaleAmount: 9900
|
||||
saleEndDate: new Date('2015-09-05')
|
||||
onSale: false
|
||||
|
||||
events:
|
||||
'click #pay-button': 'onPayButton'
|
||||
|
||||
subscriptions:
|
||||
'stripe:received-token': 'onStripeReceivedToken'
|
||||
|
||||
constructor: (options) ->
|
||||
super(options)
|
||||
@description = $.i18n.t('subscribe.stripe_description_year_sale')
|
||||
displayAmount = (@yearSaleAmount / 100).toFixed(2)
|
||||
@payButtonText = "#{$.i18n.t('subscribe.sale_view_button')} $#{displayAmount}"
|
||||
@heroes = new CocoCollection([], {model: ThangType})
|
||||
@heroes.url = '/db/thang.type?view=heroes'
|
||||
@heroes.setProjection ['original','name','heroClass','description', 'gems','extendedName','i18n']
|
||||
@heroes.comparator = 'gems'
|
||||
@listenToOnce @heroes, 'sync', @onHeroesLoaded
|
||||
@supermodel.loadCollection(@heroes, 'heroes')
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.hasSubscription = me.get('stripe')?.sponsorID
|
||||
c.heroes = @heroes.models
|
||||
c.payButtonText = @payButtonText
|
||||
c.saleEndDate = @saleEndDate
|
||||
c.state = @state
|
||||
c.stateMessage = @stateMessage
|
||||
c
|
||||
|
||||
onHeroesLoaded: ->
|
||||
@formatHero hero for hero in @heroes.models
|
||||
|
||||
formatHero: (hero) ->
|
||||
hero.name = utils.i18n hero.attributes, 'extendedName'
|
||||
hero.name ?= utils.i18n hero.attributes, 'name'
|
||||
hero.description = utils.i18n hero.attributes, 'description'
|
||||
hero.class = hero.get('heroClass') or 'Warrior'
|
||||
|
||||
onPayButton: ->
|
||||
return @openModalView new AuthModal() if me.isAnonymous()
|
||||
@state = undefined
|
||||
@stateMessage = undefined
|
||||
@render()
|
||||
|
||||
# Show Stripe handler
|
||||
application.tracker?.trackEvent 'Started sale landing page subscription purchase'
|
||||
@timestampForPurchase = new Date().getTime()
|
||||
stripeHandler.open
|
||||
amount: @yearSaleAmount
|
||||
description: @description
|
||||
bitcoin: true
|
||||
alipay: if me.get('country') is 'china' or (me.get('preferredLanguage') or 'en-US')[...2] is 'zh' then true else 'auto'
|
||||
|
||||
onStripeReceivedToken: (e) ->
|
||||
@state = 'purchasing'
|
||||
@render?()
|
||||
|
||||
# Call year sale API
|
||||
data =
|
||||
stripe:
|
||||
token: e.token.id
|
||||
timestamp: @timestampForPurchase
|
||||
jqxhr = $.post('/db/subscription/-/year_sale', data)
|
||||
jqxhr.done (data, textStatus, jqXHR) =>
|
||||
application.tracker?.trackEvent 'Finished sale landing page subscription purchase', value: @yearSaleAmount
|
||||
me.fetch(cache: false).always =>
|
||||
app.router.navigate '/play', trigger: true
|
||||
jqxhr.fail (xhr, textStatus, errorThrown) =>
|
||||
console.error 'We got an error subscribing with Stripe from our server:', textStatus, errorThrown
|
||||
application.tracker?.trackEvent 'Failed to finish 1 year subscription purchase', status: textStatus
|
||||
if xhr.status is 402
|
||||
@state = 'declined'
|
||||
@stateMessage = arguments[2]
|
||||
else
|
||||
@state = 'unknown_error'
|
||||
@stateMessage = "#{xhr.status}: #{xhr.responseText}"
|
||||
@render?()
|
|
@ -131,7 +131,7 @@ module.exports = class DiplomatView extends ContributeClassView
|
|||
hi: [] # मानक हिन्दी, Hindi
|
||||
ur: [] # اُردُو, Urdu
|
||||
ms: [] # Bahasa Melayu, Bahasa Malaysia
|
||||
ca: ['ArniMcFrag'] # Català, Catalan
|
||||
ca: ['ArniMcFrag', 'Nainufar'] # Català, Catalan
|
||||
gl: ['mcaeiror'] # Galego, Galician
|
||||
'mk-MK': ['SuperPranx'] # Македонски, Macedonian
|
||||
eo: [] # Esperanto, Esperanto
|
||||
|
|
|
@ -3,16 +3,14 @@ template = require 'templates/core/subscribe-modal'
|
|||
stripeHandler = require 'core/services/stripe'
|
||||
utils = require 'core/utils'
|
||||
AuthModal = require 'views/core/AuthModal'
|
||||
Products = require 'collections/Products'
|
||||
|
||||
module.exports = class SubscribeModal extends ModalView
|
||||
id: 'subscribe-modal'
|
||||
template: template
|
||||
plain: true
|
||||
closesOnClickOutside: false
|
||||
product:
|
||||
amount: 999
|
||||
planID: 'basic'
|
||||
yearAmount: 9900
|
||||
planID: 'basic'
|
||||
|
||||
subscriptions:
|
||||
'stripe:received-token': 'onStripeReceivedToken'
|
||||
|
@ -27,6 +25,13 @@ module.exports = class SubscribeModal extends ModalView
|
|||
constructor: (options) ->
|
||||
super(options)
|
||||
@state = 'standby'
|
||||
@products = new Products()
|
||||
@supermodel.loadCollection(@products, 'products')
|
||||
|
||||
onLoaded: ->
|
||||
@basicProduct = @products.findWhere { name: 'basic_subscription' }
|
||||
@yearProduct = @products.findWhere { name: 'year_subscription' }
|
||||
super()
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -51,11 +56,15 @@ module.exports = class SubscribeModal extends ModalView
|
|||
application.tracker?.trackEvent 'Subscription ask parent button click'
|
||||
|
||||
setupParentInfoPopover: ->
|
||||
return unless @products.size()
|
||||
popoverTitle = $.i18n.t 'subscribe.parents_title'
|
||||
levelsCompleted = me.get('stats')?.gamesCompleted or 'several'
|
||||
popoverContent = "<p>" + $.i18n.t('subscribe.parents_blurb1', nLevels: levelsCompleted) + "</p>"
|
||||
popoverContent += "<p>" + $.i18n.t('subscribe.parents_blurb1a') + "</p>"
|
||||
popoverContent += "<p>" + $.i18n.t('subscribe.parents_blurb2') + "</p>"
|
||||
popoverContent += "<p>" + $.i18n.t('subscribe.parents_blurb2a') + "</p>"
|
||||
price = (@products.findWhere({'name': 'basic_subscription'}).get('amount') / 100).toFixed(2)
|
||||
# TODO: Update i18next and use its own interpolation system instead
|
||||
popoverContent = popoverContent.replace('{{price}}', price)
|
||||
popoverContent += "<p>" + $.i18n.t('subscribe.parents_blurb3') + "</p>"
|
||||
#popoverContent = popoverContent.replace /9[.,]99/g, '3.99' # Sale
|
||||
@$el.find('#parents-info').popover(
|
||||
|
@ -70,9 +79,15 @@ module.exports = class SubscribeModal extends ModalView
|
|||
application.tracker?.trackEvent 'Subscription parent hover'
|
||||
|
||||
setupPaymentMethodsInfoPopover: ->
|
||||
return unless @products.size()
|
||||
popoverTitle = $.i18n.t('subscribe.payment_methods_title')
|
||||
three_month_price = (@products.findWhere({'name': 'basic_subscription'}).get('amount') * 3 / 100).toFixed(2)
|
||||
year_price = (@products.findWhere({name: 'year_subscription'}).get('amount') / 100).toFixed(2)
|
||||
popoverTitle += '<button type="button" class="close" onclick="$('#payment-methods-info').popover('hide');">×</button>'
|
||||
popoverContent = "<p>" + $.i18n.t('subscribe.payment_methods_blurb1') + "</p>"
|
||||
popoverContent = "<p>" + $.i18n.t('subscribe.payment_methods_blurb1a') + "</p>"
|
||||
# TODO: Update i18next and use its own interpolation system instead
|
||||
popoverContent = popoverContent.replace('{{three_month_price}}', three_month_price)
|
||||
popoverContent = popoverContent.replace('{{year_price}}', year_price)
|
||||
popoverContent += "<p>" + $.i18n.t('subscribe.payment_methods_blurb2') + " <a href='mailto:support@codecombat.com'>support@codecombat.com</a>."
|
||||
@$el.find('#payment-methods-info').popover(
|
||||
animation: true
|
||||
|
@ -109,12 +124,13 @@ module.exports = class SubscribeModal extends ModalView
|
|||
@$el.find('.parent-button').popover('hide')
|
||||
|
||||
onClickPurchaseButton: (e) ->
|
||||
return unless @basicProduct and @yearProduct
|
||||
@playSound 'menu-button-click'
|
||||
return @openModalView new AuthModal() if me.get('anonymous')
|
||||
application.tracker?.trackEvent 'Started subscription purchase'
|
||||
options = {
|
||||
description: $.i18n.t('subscribe.stripe_description')
|
||||
amount: @product.amount
|
||||
amount: @basicProduct.get('amount')
|
||||
alipay: if me.get('country') is 'china' or (me.get('preferredLanguage') or 'en-US')[...2] is 'zh' then true else 'auto'
|
||||
alipayReusable: true
|
||||
}
|
||||
|
@ -136,9 +152,11 @@ module.exports = class SubscribeModal extends ModalView
|
|||
@playSound 'menu-button-click'
|
||||
return @openModalView new AuthModal() if me.get('anonymous')
|
||||
application.tracker?.trackEvent 'Started 1 year subscription purchase'
|
||||
discount = @basicProduct.get('amount') * 12 - @yearProduct.get('amount')
|
||||
discountString = (discount/100).toFixed(2)
|
||||
options =
|
||||
description: $.i18n.t('subscribe.stripe_description_year_sale')
|
||||
amount: @product.yearAmount
|
||||
description: $.i18n.t('subscribe.stripe_description_year_sale1').replace('{{discount}}', discountString)
|
||||
amount: @yearProduct.get('amount')
|
||||
alipay: if me.get('country') is 'china' or (me.get('preferredLanguage') or 'en-US')[...2] is 'zh' then true else 'auto'
|
||||
alipayReusable: true
|
||||
@purchasedAmount = options.amount
|
||||
|
@ -148,15 +166,15 @@ module.exports = class SubscribeModal extends ModalView
|
|||
@state = 'purchasing'
|
||||
@render()
|
||||
|
||||
if @purchasedAmount is @product.amount
|
||||
if @purchasedAmount is @basicProduct.get('amount')
|
||||
stripe = _.clone(me.get('stripe') ? {})
|
||||
stripe.planID = @product.planID
|
||||
stripe.planID = @basicProduct.get('planID')
|
||||
stripe.token = e.token.id
|
||||
me.set 'stripe', stripe
|
||||
@listenToOnce me, 'sync', @onSubscriptionSuccess
|
||||
@listenToOnce me, 'error', @onSubscriptionError
|
||||
me.patch({headers: {'X-Change-Plan': 'true'}})
|
||||
else if @purchasedAmount is @product.yearAmount
|
||||
else if @purchasedAmount is @yearProduct.get('amount')
|
||||
# Purchasing a year
|
||||
data =
|
||||
stripe:
|
||||
|
|
|
@ -9,12 +9,13 @@ stripeHandler = require 'core/services/stripe'
|
|||
template = require 'templates/courses/purchase-courses-view'
|
||||
User = require 'models/User'
|
||||
utils = require 'core/utils'
|
||||
Products = require 'collections/Products'
|
||||
|
||||
module.exports = class PurchaseCoursesView extends RootView
|
||||
id: 'purchase-courses-view'
|
||||
template: template
|
||||
numberOfStudents: 30
|
||||
pricePerStudent: 4
|
||||
pricePerStudent: 0
|
||||
|
||||
initialize: (options) ->
|
||||
@listenTo stripeHandler, 'received-token', @onStripeReceivedToken
|
||||
|
@ -29,13 +30,19 @@ module.exports = class PurchaseCoursesView extends RootView
|
|||
@prepaids.comparator = '_id'
|
||||
@prepaids.fetchByCreator(me.id)
|
||||
@supermodel.loadCollection(@prepaids, 'prepaids')
|
||||
@products = new Products()
|
||||
@supermodel.loadCollection(@products, 'products')
|
||||
super(options)
|
||||
|
||||
events:
|
||||
'input #students-input': 'onInputStudentsInput'
|
||||
'click #purchase-btn': 'onClickPurchaseButton'
|
||||
|
||||
onLoaded: ->
|
||||
@pricePerStudent = @products.findWhere({name: 'course'}).get('amount')
|
||||
super()
|
||||
|
||||
getPriceString: -> '$' + (@getPrice()).toFixed(2)
|
||||
getPriceString: -> '$' + (@getPrice()/100).toFixed(2)
|
||||
getPrice: -> @pricePerStudent * @numberOfStudents
|
||||
|
||||
onceClassroomsSync: ->
|
||||
|
@ -80,7 +87,7 @@ module.exports = class PurchaseCoursesView extends RootView
|
|||
application.tracker?.trackEvent 'Started course prepaid purchase', {
|
||||
price: @pricePerStudent, students: @numberOfStudents}
|
||||
stripeHandler.open
|
||||
amount: @numberOfStudents * @pricePerStudent * 100
|
||||
amount: @numberOfStudents * @pricePerStudent
|
||||
description: "Full course access for #{@numberOfStudents} students"
|
||||
bitcoin: true
|
||||
alipay: if me.get('country') is 'china' or (me.get('preferredLanguage') or 'en-US')[...2] is 'zh' then true else 'auto'
|
||||
|
|
|
@ -26,9 +26,8 @@ module.exports = class SimulateTabView extends CocoView
|
|||
onLoaded: ->
|
||||
super()
|
||||
@render()
|
||||
# Save our MongoDB oplog!
|
||||
#if (document.location.hash is '#simulate' or @options.level.get('type') is 'course-ladder') and not @simulator
|
||||
# @startSimulating()
|
||||
if (document.location.hash is '#simulate' or @options.level.get('type') is 'course-ladder') and not @simulator
|
||||
@startSimulating()
|
||||
|
||||
getRenderData: ->
|
||||
ctx = super()
|
||||
|
|
|
@ -427,7 +427,7 @@ module.exports = class PlayLevelView extends RootView
|
|||
|
||||
shouldSimulate: ->
|
||||
return true if @getQueryVariable('simulate') is true
|
||||
return false # Save our MongoDB oplog!
|
||||
return false if @getQueryVariable('simulate') is false
|
||||
stillBuggy = true # Keep this true while we still haven't fixed the zombie worker problem when simulating the more difficult levels on Chrome
|
||||
defaultCores = 2
|
||||
cores = window.navigator.hardwareConcurrency or defaultCores # Available on Chrome/Opera, soon Safari
|
||||
|
|
|
@ -497,7 +497,9 @@ module.exports = class InventoryModal extends ModalView
|
|||
@playSound 'menu-button-click'
|
||||
@showLoading()
|
||||
ua = navigator.userAgent.toLowerCase()
|
||||
unless me.isAdmin() or hasGoneFullScreenOnce and (/safari/.test(ua) and not /chrome/.test(ua)) or $(window).height() >= 658 # Min vertical resolution needed at 1366px wide
|
||||
isSafari = /safari/.test(ua) and not /chrome/.test(ua)
|
||||
isTooShort = $(window).height() < 658 # Min vertical resolution needed at 1366px wide
|
||||
if isTooShort and not me.isAdmin() and not hasGoneFullScreenOnce and not isSafari
|
||||
@toggleFullscreen()
|
||||
hasGoneFullScreenOnce = true
|
||||
@updateConfig =>
|
||||
|
|
|
@ -3,18 +3,13 @@ template = require 'templates/play/modal/buy-gems-modal'
|
|||
stripeHandler = require 'core/services/stripe'
|
||||
utils = require 'core/utils'
|
||||
SubscribeModal = require 'views/core/SubscribeModal'
|
||||
Products = require 'collections/Products'
|
||||
|
||||
module.exports = class BuyGemsModal extends ModalView
|
||||
id: 'buy-gems-modal'
|
||||
template: template
|
||||
plain: true
|
||||
|
||||
originalProducts: [
|
||||
{ price: '$4.99', gems: 5000, amount: 499, id: 'gems_5', i18n: 'buy_gems.few_gems' }
|
||||
{ price: '$9.99', gems: 11000, amount: 999, id: 'gems_10', i18n: 'buy_gems.pile_gems' }
|
||||
{ price: '$19.99', gems: 25000, amount: 1999, id: 'gems_20', i18n: 'buy_gems.chest_gems' }
|
||||
]
|
||||
|
||||
subscriptions:
|
||||
'ipad:products': 'onIPadProducts'
|
||||
'ipad:iap-complete': 'onIAPComplete'
|
||||
|
@ -29,22 +24,21 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
super(options)
|
||||
@timestampForPurchase = new Date().getTime()
|
||||
@state = 'standby'
|
||||
@products = new Products()
|
||||
@products.comparator = 'amount'
|
||||
if application.isIPadApp
|
||||
@products = []
|
||||
Backbone.Mediator.publish 'buy-gems-modal:update-products'
|
||||
else
|
||||
@products = @originalProducts
|
||||
@supermodel.loadCollection(@products, 'products')
|
||||
$.post '/db/payment/check-stripe-charges', (something, somethingElse, jqxhr) =>
|
||||
if jqxhr.status is 201
|
||||
@state = 'recovered_charge'
|
||||
@render()
|
||||
|
||||
getRenderData: ->
|
||||
c = super()
|
||||
c.products = @products
|
||||
c.state = @state
|
||||
c.stateMessage = @stateMessage
|
||||
return c
|
||||
onLoaded: ->
|
||||
@products.reset @products.filter (product) -> _.string.startsWith(product.get('name'), 'gems_')
|
||||
super()
|
||||
|
||||
afterRender: ->
|
||||
super()
|
||||
|
@ -56,19 +50,20 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
@playSound 'game-menu-close'
|
||||
|
||||
onIPadProducts: (e) ->
|
||||
newProducts = []
|
||||
for iapProduct in e.products
|
||||
localProduct = _.find @originalProducts, { id: iapProduct.id }
|
||||
continue unless localProduct
|
||||
localProduct.price = iapProduct.price
|
||||
newProducts.push localProduct
|
||||
@products = _.sortBy newProducts, 'gems'
|
||||
@render()
|
||||
# TODO: Update to handle new products collection
|
||||
# newProducts = []
|
||||
# for iapProduct in e.products
|
||||
# localProduct = _.find @originalProducts, { id: iapProduct.id }
|
||||
# continue unless localProduct
|
||||
# localProduct.price = iapProduct.price
|
||||
# newProducts.push localProduct
|
||||
# @products = _.sortBy newProducts, 'gems'
|
||||
# @render()
|
||||
|
||||
onClickProductButton: (e) ->
|
||||
@playSound 'menu-button-click'
|
||||
productID = $(e.target).closest('button').val()
|
||||
product = _.find @products, { id: productID }
|
||||
product = @products.findWhere { name: productID }
|
||||
|
||||
if application.isIPadApp
|
||||
Backbone.Mediator.publish 'buy-gems-modal:purchase-initiated', { productID: productID }
|
||||
|
@ -76,8 +71,8 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
else
|
||||
application.tracker?.trackEvent 'Started gem purchase', { productID: productID }
|
||||
stripeHandler.open({
|
||||
description: $.t(product.i18n)
|
||||
amount: product.amount
|
||||
description: $.t(product.get('i18n'))
|
||||
amount: product.get('amount')
|
||||
bitcoin: true
|
||||
alipay: if me.get('country') is 'china' or (me.get('preferredLanguage') or 'en-US')[...2] is 'zh' then true else 'auto'
|
||||
})
|
||||
|
@ -86,7 +81,7 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
|
||||
onStripeReceivedToken: (e) ->
|
||||
data = {
|
||||
productID: @productBeingPurchased.id
|
||||
productID: @productBeingPurchased.get('name')
|
||||
stripe: {
|
||||
token: e.token.id
|
||||
timestamp: @timestampForPurchase
|
||||
|
@ -97,8 +92,8 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
jqxhr = $.post('/db/payment', data)
|
||||
jqxhr.done(=>
|
||||
application.tracker?.trackEvent 'Finished gem purchase',
|
||||
productID: @productBeingPurchased.id
|
||||
value: @productBeingPurchased.amount
|
||||
productID: @productBeingPurchased.get('name')
|
||||
value: @productBeingPurchased.get('amount')
|
||||
document.location.reload()
|
||||
)
|
||||
jqxhr.fail(=>
|
||||
|
@ -116,7 +111,7 @@ module.exports = class BuyGemsModal extends ModalView
|
|||
)
|
||||
|
||||
onIAPComplete: (e) ->
|
||||
product = _.find @products, { id: e.productID }
|
||||
product = @products.findWhere { name: e.productID }
|
||||
purchased = me.get('purchased') ? {}
|
||||
purchased = _.clone purchased
|
||||
purchased.gems ?= 0
|
||||
|
|
|
@ -1,65 +1,41 @@
|
|||
// Average level playtimes by campaign
|
||||
// Average level playtimes in seconds by campaign, broken up by course and campaign levels
|
||||
|
||||
// Usage:
|
||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||
|
||||
// NOTE: faster to use find() instead of aggregate()
|
||||
// NOTE: faster to ask for one level at a time. also keeps levels in campaign order
|
||||
// NOTE: faster to ask for one level at a time.
|
||||
|
||||
// Excluded for one reason or another
|
||||
// Some relevant code: https://github.com/codecombat/codecombat/blob/master/app/views/play/CampaignView.coffee#L281-L292
|
||||
var excludedLevels = ['deadly-dungeon-rescue', 'kithgard-brawl', 'cavern-survival', 'kithgard-mastery', 'destroying-angel', 'kithgard-apprentice', 'wild-horses', 'lost-viking', 'forest-flower-grove', 'boulder-woods', 'the-trials'];
|
||||
var courseCampaigns = ['intro', 'course-2', 'course-3', 'course-4'];
|
||||
var individualCampaigns = ['dungeon', 'forest', 'desert', 'mountain'];
|
||||
|
||||
var scriptStartTime = new Date();
|
||||
var startDay = '2015-07-01';
|
||||
var endDay = '2015-08-06';
|
||||
var startDay = '2015-12-06';
|
||||
var endDay = '2015-12-13';
|
||||
|
||||
log("Dates: " + startDay + " to " + endDay);
|
||||
print("Dates: " + startDay + " to " + endDay);
|
||||
|
||||
// Print out playtimes for each campaign
|
||||
var campaigns = getCampaigns();
|
||||
var campaigns = getCampaigns(courseCampaigns);
|
||||
|
||||
for (var i = 0; i < campaigns.length; i++) {
|
||||
var campaign = campaigns[i];
|
||||
// if (campaign.slug !== 'dungeon') continue;
|
||||
print(campaign.slug + " (free)");
|
||||
var total = 0;
|
||||
|
||||
for (var j = 0; j < campaign.free.length; j++) {
|
||||
var levelSlug = campaign.free[j];
|
||||
if (excludedLevels.indexOf(levelSlug) >= 0) continue;
|
||||
var data = getPlaytimes([levelSlug]);
|
||||
print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug);
|
||||
total += data[levelSlug];
|
||||
}
|
||||
// print(parseInt(total/60/60) + "\t\t total hours");
|
||||
total = 0;
|
||||
|
||||
print(campaign.slug + " (paid)");
|
||||
for (var j = 0; j < campaign.paid.length; j++) {
|
||||
var levelSlug = campaign.paid[j];
|
||||
if (excludedLevels.indexOf(levelSlug) >= 0) continue;
|
||||
var data = getPlaytimes([levelSlug]);
|
||||
if (data[levelSlug]) {
|
||||
print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug);
|
||||
total += data[levelSlug];
|
||||
print(campaign.slug);
|
||||
print("Sessions\tAverage\tSessions\tAverage\tLevel");
|
||||
for (var j = 0; j < campaign.levelSlugs.length; j++) {
|
||||
var levelSlug = campaign.levelSlugs[j];
|
||||
var levelPlaytimes = getPlaytimes([levelSlug]);
|
||||
if (levelPlaytimes[levelSlug]) {
|
||||
print(levelPlaytimes[levelSlug].campaign.count,
|
||||
'\t', levelPlaytimes[levelSlug].campaign.average,
|
||||
'\t', levelPlaytimes[levelSlug].course.count,
|
||||
'\t', levelPlaytimes[levelSlug].course.average,
|
||||
'\t', levelSlug);
|
||||
}
|
||||
else {
|
||||
print("0\t0\t" + levelSlug);
|
||||
print(0, '\t', 0, '\t', 0, '\t', 0, '\t', levelSlug);
|
||||
}
|
||||
}
|
||||
// print(parseInt(total/60/60) + "\t\t total hours");
|
||||
total = 0;
|
||||
|
||||
print(campaign.slug + " (replayable)");
|
||||
for (var j = 0; j < campaign.replayable.length; j++) {
|
||||
var levelSlug = campaign.replayable[j];
|
||||
if (excludedLevels.indexOf(levelSlug) >= 0) continue;
|
||||
var data = getPlaytimes([levelSlug]);
|
||||
print(data[levelSlug].average + "\t" + data[levelSlug].count + "\t" + levelSlug);
|
||||
total += data[levelSlug];
|
||||
}
|
||||
// print(parseInt(total/60/60) + "\t\t total hours");
|
||||
|
||||
// break;
|
||||
}
|
||||
|
||||
|
@ -79,32 +55,32 @@ function objectIdWithTimestamp(timestamp) {
|
|||
return constructedObjectId
|
||||
}
|
||||
|
||||
function getCampaigns() {
|
||||
function getCampaigns(campaignSlugs) {
|
||||
var campaigns = [];
|
||||
var cursor = db.campaigns.find({}, {slug: 1, levels: 1});
|
||||
var cursor = db.campaigns.find({slug: {$in: campaignSlugs}}, {slug: 1, levels: 1});
|
||||
var allFree = 0;
|
||||
var allpaid = 0;
|
||||
while (cursor.hasNext()) {
|
||||
var doc = cursor.next();
|
||||
if (doc.slug === 'auditions') continue;
|
||||
var campaign = {slug: doc.slug, free: [], paid: [], replayable: []};
|
||||
var campaign = {slug: doc.slug, levelSlugs: []};
|
||||
for (var levelID in doc.levels) {
|
||||
if (doc.levels[levelID].replayable) {
|
||||
campaign.replayable.push(doc.levels[levelID].slug);
|
||||
}
|
||||
else if (doc.levels[levelID].requiresSubscription) {
|
||||
campaign.paid.push(doc.levels[levelID].slug);
|
||||
}
|
||||
else {
|
||||
campaign.free.push(doc.levels[levelID].slug);
|
||||
}
|
||||
campaign.levelSlugs.push(doc.levels[levelID].slug);
|
||||
}
|
||||
campaigns.push(campaign);
|
||||
}
|
||||
|
||||
campaigns.sort(function (a, b) {
|
||||
if (campaignSlugs.indexOf(a.slug) < campaignSlugs.indexOf(b.slug)){
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
return campaigns;
|
||||
}
|
||||
|
||||
function getPlaytimes(levelSlugs) {
|
||||
// printjson(levelSlugs);
|
||||
var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
|
||||
var endObj = objectIdWithTimestamp(ISODate(endDay + "T00:00:00.000Z"))
|
||||
var cursor = db['level.sessions'].find({
|
||||
|
@ -116,21 +92,49 @@ function getPlaytimes(levelSlugs) {
|
|||
{_id: {$gte: startObj}},
|
||||
{_id: {$lt: endObj}}
|
||||
]
|
||||
});
|
||||
}, {heroConfig: 1, levelID: 1, playtime: 1});
|
||||
|
||||
var playtimes = {};
|
||||
while (cursor.hasNext()) {
|
||||
var myDoc = cursor.next();
|
||||
var levelID = myDoc.levelID;
|
||||
if (!playtimes[levelID]) playtimes[levelID] = [];
|
||||
playtimes[levelID].push(myDoc.playtime);
|
||||
|
||||
if (!playtimes[levelID]) playtimes[levelID] = {campaign: [], course: []};
|
||||
if (myDoc.heroConfig) {
|
||||
playtimes[levelID].campaign.push(myDoc.playtime);
|
||||
}
|
||||
else {
|
||||
playtimes[levelID].course.push(myDoc.playtime);
|
||||
}
|
||||
}
|
||||
// printjson(playtimes);
|
||||
|
||||
var data = {};
|
||||
for (levelID in playtimes) {
|
||||
var total = playtimes[levelID].reduce(function(a, b) {return a + b;});
|
||||
data[levelID] = {count: playtimes[levelID].length, total: total};
|
||||
data[levelID]['average'] = parseInt(total / playtimes[levelID].length);
|
||||
var campaignTotal = 0;
|
||||
var courseTotal = 0;
|
||||
if (playtimes[levelID].campaign.length > 0) {
|
||||
campaignTotal = playtimes[levelID].campaign.reduce(function(a, b) {return a + b;});
|
||||
}
|
||||
if (playtimes[levelID].course.length > 0) {
|
||||
courseTotal = playtimes[levelID].course.reduce(function(a, b) {return a + b;});
|
||||
}
|
||||
|
||||
var campaignAverage = parseInt(playtimes[levelID].campaign.length > 0 ? parseInt(campaignTotal / playtimes[levelID].campaign.length): 0);
|
||||
var courseAverage = parseInt(playtimes[levelID].course.length > 0 ? parseInt(courseTotal / playtimes[levelID].course.length): 0);
|
||||
|
||||
data[levelID] = {
|
||||
campaign: {
|
||||
count: playtimes[levelID].campaign.length,
|
||||
total: campaignTotal,
|
||||
average: campaignAverage
|
||||
},
|
||||
course: {
|
||||
count: playtimes[levelID].course.length,
|
||||
total: courseTotal,
|
||||
average: courseAverage
|
||||
}
|
||||
};
|
||||
}
|
||||
return data;
|
||||
}
|
||||
|
|
106
scripts/analytics/mongodb/queries/campaignCompletionCounts.js
Normal file
|
@ -0,0 +1,106 @@
|
|||
// Campaign completion counts
|
||||
|
||||
// Usage:
|
||||
// mongo <address>:<port>/<database> <script file> -u <username> -p <password>
|
||||
|
||||
var courseCampaigns = ['intro', 'course-2', 'course-3', 'course-4'];
|
||||
var individualCampaigns = ['dungeon', 'forest', 'desert', 'mountain'];
|
||||
|
||||
var scriptStartTime = new Date();
|
||||
var startDay = '2015-11-08';
|
||||
var endDay = '2015-11-15'; // Not inclusive
|
||||
|
||||
log("Dates: " + startDay + " to " + endDay);
|
||||
|
||||
var campaigns = getCampaigns(courseCampaigns);
|
||||
// var campaigns = getCampaigns(individualCampaigns);
|
||||
// printjson(campaigns);
|
||||
|
||||
for (var i = 0; i < campaigns.length; i++) {
|
||||
var campaign = campaigns[i];
|
||||
print(campaign.slug);
|
||||
print("Total\tCampaign\tCourse\tLevel");
|
||||
var completionCounts = getCompletionCounts(campaign.levelSlugs);
|
||||
for (var j = 0; j < campaign.levelSlugs.length; j++) {
|
||||
var levelSlug = campaign.levelSlugs[j];
|
||||
if (completionCounts[levelSlug]) {
|
||||
print(completionCounts[levelSlug].campaign + completionCounts[levelSlug].course,
|
||||
'\t', completionCounts[levelSlug].campaign,
|
||||
'\t', completionCounts[levelSlug].course,
|
||||
'\t', levelSlug);
|
||||
}
|
||||
else {
|
||||
print(0, '\t', 0, '\t', 0, '\t', levelSlug);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
log("Script runtime: " + (new Date() - scriptStartTime));
|
||||
|
||||
function log(str) {
|
||||
print(new Date().toISOString() + " " + str);
|
||||
}
|
||||
|
||||
function objectIdWithTimestamp(timestamp) {
|
||||
// Convert string date to Date object (otherwise assume timestamp is a date)
|
||||
if (typeof(timestamp) == 'string') timestamp = new Date(timestamp);
|
||||
// Convert date object to hex seconds since Unix epoch
|
||||
var hexSeconds = Math.floor(timestamp/1000).toString(16);
|
||||
// Create an ObjectId with that hex timestamp
|
||||
var constructedObjectId = ObjectId(hexSeconds + "0000000000000000");
|
||||
return constructedObjectId
|
||||
}
|
||||
|
||||
function getCampaigns(campaignSlugs) {
|
||||
var campaigns = [];
|
||||
var cursor = db.campaigns.find({slug: {$in: campaignSlugs}}, {slug: 1, levels: 1});
|
||||
var allFree = 0;
|
||||
var allpaid = 0;
|
||||
while (cursor.hasNext()) {
|
||||
var doc = cursor.next();
|
||||
if (doc.slug === 'auditions') continue;
|
||||
var campaign = {slug: doc.slug, levelSlugs: []};
|
||||
for (var levelID in doc.levels) {
|
||||
campaign.levelSlugs.push(doc.levels[levelID].slug);
|
||||
}
|
||||
campaigns.push(campaign);
|
||||
}
|
||||
|
||||
campaigns.sort(function (a, b) {
|
||||
if (campaignSlugs.indexOf(a.slug) < campaignSlugs.indexOf(b.slug)){
|
||||
return -1;
|
||||
}
|
||||
return 1;
|
||||
});
|
||||
return campaigns;
|
||||
}
|
||||
|
||||
function getCompletionCounts(levelSlugs) {
|
||||
var startObj = objectIdWithTimestamp(ISODate(startDay + "T00:00:00.000Z"));
|
||||
var endObj = objectIdWithTimestamp(ISODate(endDay + "T00:00:00.000Z"))
|
||||
var cursor = db['level.sessions'].find({
|
||||
$and:
|
||||
[
|
||||
{"state.complete": true},
|
||||
{levelID: {$in: levelSlugs}},
|
||||
{_id: {$gte: startObj}},
|
||||
{_id: {$lt: endObj}}
|
||||
]
|
||||
}, {heroConfig: 1, levelID: 1});
|
||||
|
||||
var completionCounts = {};
|
||||
while (cursor.hasNext()) {
|
||||
var myDoc = cursor.next();
|
||||
var levelID = myDoc.levelID;
|
||||
|
||||
if (!completionCounts[levelID]) completionCounts[levelID] = {campaign: 0, course: 0};
|
||||
if (myDoc.heroConfig) {
|
||||
completionCounts[levelID].campaign++;
|
||||
}
|
||||
else {
|
||||
completionCounts[levelID].course++;
|
||||
}
|
||||
}
|
||||
|
||||
return completionCounts;
|
||||
}
|
|
@ -438,7 +438,6 @@ function getActiveUserCounts(startDay, activeUserEvents) {
|
|||
if (!dayUserMap[day]) dayUserMap[day] = {};
|
||||
dayUserMap[day][user] = true;
|
||||
}
|
||||
// printjson(dayUserMap['2015-11-01']);
|
||||
|
||||
var activeUsersCounts = {};
|
||||
var monthlyActives = [];
|
||||
|
@ -474,7 +473,8 @@ function getActiveClassCounts(startDay) {
|
|||
'Active classes managed subscription': [],
|
||||
'Active classes bulk subscription': [],
|
||||
'Active classes prepaid': [],
|
||||
'Active classes course': [],
|
||||
'Active classes course free': [],
|
||||
'Active classes course paid': []
|
||||
};
|
||||
var userPlayedMap = {};
|
||||
|
||||
|
@ -539,10 +539,10 @@ function getActiveClassCounts(startDay) {
|
|||
}
|
||||
}
|
||||
|
||||
// Prepaids terminal_subscription & course
|
||||
// Prepaids terminal_subscription
|
||||
bulkSubGroups = {};
|
||||
cursor = db.prepaids.find(
|
||||
{$and: [{type: {$in: ['terminal_subscription', 'course']}}, {$where: 'this.redeemers && this.redeemers.length >= ' + minGroupSize}]},
|
||||
{$and: [{type: 'terminal_subscription'}, {$where: 'this.redeemers && this.redeemers.length >= ' + minGroupSize}]},
|
||||
{creator: 1, type: 1, redeemers: 1}
|
||||
);
|
||||
while (cursor.hasNext()) {
|
||||
|
@ -553,17 +553,37 @@ function getActiveClassCounts(startDay) {
|
|||
userPlayedMap[doc.redeemers[i].userID.valueOf()] = [];
|
||||
members.push(doc.redeemers[i].userID.valueOf());
|
||||
}
|
||||
var event = doc.type == 'terminal_subscription' ? 'Active classes prepaid' : 'Active classes course';
|
||||
classes[event].push({
|
||||
classes['Active classes prepaid'].push({
|
||||
owner: owner,
|
||||
members: members,
|
||||
activeDayMap: {}
|
||||
});
|
||||
}
|
||||
|
||||
// printjson(classes);
|
||||
// Classrooms
|
||||
var classroomCourseInstancesMap = {};
|
||||
cursor = db.course.instances.find(
|
||||
{$where: 'this.members && this.members.length >= ' + minGroupSize},
|
||||
{classroomID: 1, courseID: 1, members: 1, ownerID: 1}
|
||||
);
|
||||
while (cursor.hasNext()) {
|
||||
var doc = cursor.next();
|
||||
var owner = doc.ownerID.valueOf();
|
||||
var classroom = doc.classroomID ? doc.classroomID.valueOf() : doc._id.valueOf();
|
||||
var members = [];
|
||||
for (var i = 0 ; i < doc.members.length; i++) {
|
||||
userPlayedMap[doc.members[i].valueOf()] = [];
|
||||
members.push(doc.members[i].valueOf());
|
||||
}
|
||||
if (!classroomCourseInstancesMap[classroom]) classroomCourseInstancesMap[classroom] = [];
|
||||
classroomCourseInstancesMap[classroom].push({
|
||||
course: doc.courseID.valueOf(),
|
||||
owner: owner,
|
||||
members: members,
|
||||
});
|
||||
}
|
||||
|
||||
// TODO: classrooms
|
||||
// printjson(classroomCourseInstancesMap);
|
||||
|
||||
// Find all the started level events for our class members, for startDay - daysInMonth
|
||||
var startDate = ISODate(startDay + "T00:00:00.000Z");
|
||||
|
@ -573,11 +593,10 @@ function getActiveClassCounts(startDay) {
|
|||
var startObj = objectIdWithTimestamp(startDate);
|
||||
var queryParams = {$and: [
|
||||
{_id: {$gte: startObj}},
|
||||
{event: 'Started Level'},
|
||||
{user: {$in: Object.keys(userPlayedMap)}}
|
||||
{user: {$in: Object.keys(userPlayedMap)}},
|
||||
{event: 'Started Level'}
|
||||
]};
|
||||
cursor = logDB['log'].find(queryParams, {user: 1});
|
||||
// cursor = db['level.sessions'].find({$and: [{creator: {$in: Object.keys(userPlayedMap)}}, {changed: {$gte: startDate}}]}, {creator: 1, changed: 1});
|
||||
while (cursor.hasNext()) {
|
||||
var doc = cursor.next();
|
||||
userPlayedMap[doc.user].push(doc._id.getTimestamp());
|
||||
|
@ -621,6 +640,108 @@ function getActiveClassCounts(startDay) {
|
|||
endDate.setUTCDate(endDate.getUTCDate() + 1);
|
||||
}
|
||||
|
||||
// Classrooms are processed differently because they could be free or paid active classes
|
||||
var courseNameMap = {};
|
||||
cursor = db.courses.find({}, {name: 1});
|
||||
while (cursor.hasNext()) {
|
||||
var doc = cursor.next();
|
||||
courseNameMap[doc._id.valueOf()] = doc.name;
|
||||
}
|
||||
|
||||
// For each classroom, check free and paid members separately
|
||||
for (var classroom in classroomCourseInstancesMap) {
|
||||
var freeMembers = {};
|
||||
var paidMembers = {};
|
||||
var owner = null;
|
||||
for (var i = 0; i < classroomCourseInstancesMap[classroom].length; i++) {
|
||||
var courseInstance = classroomCourseInstancesMap[classroom][i];
|
||||
if (!owner) owner = courseInstance.owner;
|
||||
for (var j = 0; j < courseInstance.members.length; j++) {
|
||||
if (courseNameMap[courseInstance.course] === 'Introduction to Computer Science') {
|
||||
freeMembers[courseInstance.members[j]] = true;
|
||||
}
|
||||
else {
|
||||
paidMembers[courseInstance.members[j]] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var freeClass = {
|
||||
owner: owner,
|
||||
members: Object.keys(freeMembers),
|
||||
activeDayMap: {}
|
||||
};
|
||||
var paidClass = {
|
||||
owner: owner,
|
||||
members: Object.keys(paidMembers),
|
||||
activeDayMap: {}
|
||||
};
|
||||
|
||||
// print('Processing classroom', classroom, freeClass.members.length, paidClass.members.length);
|
||||
|
||||
startDate = ISODate(startDay + "T00:00:00.000Z");
|
||||
startDate.setUTCDate(startDate.getUTCDate() - daysInMonth);
|
||||
endDate = ISODate(startDay + "T00:00:00.000Z");
|
||||
while (endDate < todayDate) {
|
||||
var endDay = endDate.toISOString().substring(0, 10);
|
||||
|
||||
// For each paid member of current class
|
||||
var paidActiveMemberCount = 0;
|
||||
for (var j = 0; j < paidClass.members.length; j++) {
|
||||
var member = paidClass.members[j];
|
||||
|
||||
// Was member active during current timeframe?
|
||||
if (userPlayedMap[member]) {
|
||||
for (var k = 0; k < userPlayedMap[member].length; k++) {
|
||||
if (userPlayedMap[member][k] > startDate && userPlayedMap[member][k] <= endDate) {
|
||||
paidActiveMemberCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Classes active for a given day if has minGroupSize members, and at least 1/2 played in last daysInMonth days
|
||||
if (paidClass.members.length > minGroupSize && paidActiveMemberCount >= Math.round(paidClass.members.length / 2)) {
|
||||
// print('paid classroom', classroom, endDay);
|
||||
paidClass.activeDayMap[endDay] = true;
|
||||
}
|
||||
else {
|
||||
// For each free member of current class
|
||||
var freeActiveMemberCount = 0;
|
||||
for (var j = 0; j < freeClass.members.length; j++) {
|
||||
var member = freeClass.members[j];
|
||||
|
||||
// Was member active during current timeframe?
|
||||
if (userPlayedMap[member]) {
|
||||
for (var k = 0; k < userPlayedMap[member].length; k++) {
|
||||
if (userPlayedMap[member][k] > startDate && userPlayedMap[member][k] <= endDate) {
|
||||
freeActiveMemberCount++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (freeClass.members.length > minGroupSize && freeActiveMemberCount >= Math.round(freeClass.members.length / 2)) {
|
||||
// print('free classroom', classroom, endDay);
|
||||
freeClass.activeDayMap[endDay] = true;
|
||||
}
|
||||
|
||||
}
|
||||
startDate.setUTCDate(startDate.getUTCDate() + 1);
|
||||
endDate.setUTCDate(endDate.getUTCDate() + 1);
|
||||
}
|
||||
|
||||
// printjson(freeClass);
|
||||
// printjson(paidClass);
|
||||
|
||||
classes['Active classes course free'].push(freeClass);
|
||||
classes['Active classes course paid'].push(paidClass);
|
||||
}
|
||||
|
||||
// printjson(classes['Active classes course paid']);
|
||||
|
||||
var activeClassCounts = {};
|
||||
for (var event in classes) {
|
||||
if (!activeClassCounts[event]) activeClassCounts[event] = {};
|
||||
|
|
|
@ -138,11 +138,11 @@ findUserToSchool = (users) ->
|
|||
for suggestion in suggestions
|
||||
for reason in suggestion.reasons
|
||||
sum += switch reason
|
||||
when 'Course instances' then 50
|
||||
when 'Course instances' then 150
|
||||
when 'IP' then 40
|
||||
when 'Name' then 30
|
||||
when 'Referrer' then 20
|
||||
when 'Domain' then (if getDomain(target) is 'cps.edu' then 1 else 10)
|
||||
when 'Name' then 15
|
||||
when 'Domain' then (if getDomain(target) in ['cps.edu', 'mynewcaneyisd.org', 'fsusd.org'] then 1 else 10)
|
||||
when 'Clans' then 0.01
|
||||
sum
|
||||
), 0
|
||||
|
@ -205,7 +205,7 @@ findSuggestions = (target) ->
|
|||
else
|
||||
suggestions.push schoolName: otherUser.schoolName, reasons: [reason], user: otherUser
|
||||
if debugging then console.log ' Done checking referrer', (new Date()) - t0
|
||||
suggestions = _.sortBy suggestions, 'schoolName'
|
||||
suggestions = _.sortBy suggestions, (s) -> (s.schoolName or '').toLowerCase()
|
||||
suggestions = _.sortBy suggestions, (s) -> -s.reasons.length
|
||||
return suggestions
|
||||
|
||||
|
@ -215,7 +215,8 @@ usersCategorized = {}
|
|||
|
||||
sortUsers = (users) ->
|
||||
users = _.sortBy users, (u) -> -u.points
|
||||
users = _.sortBy users, ['schoolName', 'lastIP']
|
||||
users = _.sortBy users, 'lastIP'
|
||||
users = _.sortBy users, (u) -> (u.schoolName or '').toLowerCase()
|
||||
for field in ['courseInstances', 'lastIP', 'schoolName', 'domain', 'clans', 'referrer']
|
||||
userCategories[field] = categorizeUsers users, field
|
||||
topGroups[field] = _.sortBy _.keys(userCategories[field]), (key) -> -userCategories[field][key].length
|
||||
|
|
|
@ -30,7 +30,9 @@ class AnalyticsPerDayHandler extends Handler
|
|||
'Active classes managed subscription',
|
||||
'Active classes bulk subscription',
|
||||
'Active classes prepaid',
|
||||
'Active classes course']
|
||||
'Active classes course free',
|
||||
'Active classes course paid'
|
||||
]
|
||||
|
||||
AnalyticsString.find({v: {$in: events}}).exec (err, documents) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
|
|
|
@ -192,6 +192,9 @@ module.exports = class Handler
|
|||
hasLimit = false
|
||||
try
|
||||
for own key, val of req.query.conditions
|
||||
numeric = parseInt val, 10
|
||||
if not _.isNaN(numeric) and numeric + '' is val
|
||||
val = numeric
|
||||
query = query[key](val)
|
||||
hasLimit ||= key is 'limit'
|
||||
catch e
|
||||
|
|
|
@ -51,7 +51,6 @@ CourseInstanceHandler = class CourseInstanceHandler extends Handler
|
|||
if courseInstance
|
||||
console.log 'already made a course instance'
|
||||
return @sendSuccess(res, courseInstance) if courseInstance
|
||||
console.log 'making a new course instance'
|
||||
courseInstance = new CourseInstance({
|
||||
courseID: courseID
|
||||
members: [req.user.get('_id')]
|
||||
|
|
5
server/models/Mandate.coffee
Normal file
|
@ -0,0 +1,5 @@
|
|||
mongoose = require('mongoose')
|
||||
config = require '../../server_config'
|
||||
MandateSchema = new mongoose.Schema {}, {strict: false, read: config.mongo.readpref}
|
||||
|
||||
module.exports = mongoose.model('mandate', MandateSchema)
|
5
server/models/Product.coffee
Normal file
|
@ -0,0 +1,5 @@
|
|||
mongoose = require('mongoose')
|
||||
config = require '../../server_config'
|
||||
ProductSchema = new mongoose.Schema({}, {strict: false,read:config.mongo.readpref})
|
||||
|
||||
module.exports = mongoose.model('product', ProductSchema)
|
|
@ -1,4 +1,5 @@
|
|||
Payment = require './Payment'
|
||||
Product = require '../models/Product'
|
||||
User = require '../users/User'
|
||||
Handler = require '../commons/Handler'
|
||||
{handlers} = require '../commons/mapping'
|
||||
|
@ -11,30 +12,6 @@ request = require 'request'
|
|||
async = require 'async'
|
||||
apple_utils = require '../lib/apple_utils'
|
||||
|
||||
products = {
|
||||
'gems_5': {
|
||||
amount: 499
|
||||
gems: 5000
|
||||
id: 'gems_5'
|
||||
}
|
||||
|
||||
'gems_10': {
|
||||
amount: 999
|
||||
gems: 11000
|
||||
id: 'gems_10'
|
||||
}
|
||||
|
||||
'gems_20': {
|
||||
amount: 1999
|
||||
gems: 25000
|
||||
id: 'gems_20'
|
||||
}
|
||||
|
||||
'custom': {
|
||||
# amount expected in request body
|
||||
id: 'custom'
|
||||
}
|
||||
}
|
||||
|
||||
PaymentHandler = class PaymentHandler extends Handler
|
||||
modelClass: Payment
|
||||
|
@ -134,33 +111,34 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
|
||||
payment = @makeNewInstance(req)
|
||||
payment.set 'service', 'ios'
|
||||
product = products[transaction.product_id]
|
||||
|
||||
payment.set 'amount', product.amount
|
||||
payment.set 'gems', product.gems
|
||||
payment.set 'ios', {
|
||||
transactionID: transactionID
|
||||
rawReceipt: receipt
|
||||
localPrice: localPrice
|
||||
}
|
||||
|
||||
validation = @validateDocumentInput(payment.toObject())
|
||||
if validation.valid is false
|
||||
@logPaymentError(req, 'Invalid apple payment object.')
|
||||
return @sendBadInputError(res, validation.errors)
|
||||
|
||||
payment.save((err) =>
|
||||
if err
|
||||
@logPaymentError(req, 'Apple payment save error.'+err)
|
||||
return @sendDatabaseError(res, err)
|
||||
@incrementGemsFor(req.user, product.gems, (err) =>
|
||||
Product.findOne({name: transaction.product_id}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res) if not product
|
||||
payment.set 'amount', product.get('amount')
|
||||
payment.set 'gems', product.get('gems')
|
||||
payment.set 'ios', {
|
||||
transactionID: transactionID
|
||||
rawReceipt: receipt
|
||||
localPrice: localPrice
|
||||
}
|
||||
|
||||
validation = @validateDocumentInput(payment.toObject())
|
||||
if validation.valid is false
|
||||
@logPaymentError(req, 'Invalid apple payment object.')
|
||||
return @sendBadInputError(res, validation.errors)
|
||||
|
||||
payment.save((err) =>
|
||||
if err
|
||||
@logPaymentError(req, 'Apple incr db error.'+err)
|
||||
@logPaymentError(req, 'Apple payment save error.'+err)
|
||||
return @sendDatabaseError(res, err)
|
||||
@sendPaymentHipChatMessage user: req.user, payment: payment
|
||||
@sendCreated(res, @formatEntity(req, payment))
|
||||
@incrementGemsFor(req.user, product.get('gems'), (err) =>
|
||||
if err
|
||||
@logPaymentError(req, 'Apple incr db error.'+err)
|
||||
return @sendDatabaseError(res, err)
|
||||
@sendPaymentHipChatMessage user: req.user, payment: payment
|
||||
@sendCreated(res, @formatEntity(req, payment))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
|
@ -203,7 +181,6 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
|
||||
|
||||
beginStripePayment: (req, res, timestamp, productID) ->
|
||||
product = products[productID]
|
||||
|
||||
async.parallel([
|
||||
((callback) ->
|
||||
|
@ -218,6 +195,10 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
charge = _.find recentCharges.data, (c) -> c.metadata.timestamp is timestamp
|
||||
callback(null, charge)
|
||||
)
|
||||
),
|
||||
((callback) ->
|
||||
Product.findOne({name: productID}).exec (err, product) =>
|
||||
callback(err, product)
|
||||
)
|
||||
],
|
||||
|
||||
|
@ -225,7 +206,10 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
if err
|
||||
@logPaymentError(req, 'Stripe async load db error. '+err)
|
||||
return @sendDatabaseError(res, err)
|
||||
[payment, charge] = results
|
||||
[payment, charge, product] = results
|
||||
|
||||
if not product
|
||||
return @sendNotFoundError(res, 'could not find product with id '+productID)
|
||||
|
||||
if not (payment or charge)
|
||||
# Proceed normally from the beginning
|
||||
|
@ -236,7 +220,7 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
@recordStripeCharge(req, res, charge)
|
||||
|
||||
else
|
||||
return @sendSuccess(res, @formatEntity(req, payment)) if product.id is 'custom'
|
||||
return @sendSuccess(res, @formatEntity(req, payment)) if product.get('name') is 'custom'
|
||||
|
||||
# Charged Stripe and recorded it. Recalculate gems to make sure credited the purchase.
|
||||
@recalculateGemsFor(req.user, (err) =>
|
||||
|
@ -250,7 +234,7 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
)
|
||||
|
||||
chargeStripe: (req, res, product) ->
|
||||
amount = parseInt product.amount ? req.body.amount
|
||||
amount = parseInt product.get('amount') ? req.body.amount
|
||||
return @sendError(res, 400, "Invalid amount.") if isNaN(amount)
|
||||
|
||||
stripe.charges.create({
|
||||
|
@ -258,9 +242,9 @@ PaymentHandler = class PaymentHandler extends Handler
|
|||
currency: 'usd'
|
||||
customer: req.user.get('stripe')?.customerID
|
||||
metadata: {
|
||||
productID: product.id
|
||||
productID: product.get('name')
|
||||
userID: req.user._id + ''
|
||||
gems: product.gems
|
||||
gems: product.get('gems')
|
||||
timestamp: parseInt(req.body.stripe?.timestamp)
|
||||
description: req.body.description
|
||||
}
|
||||
|
|
|
@ -15,20 +15,10 @@ User = require '../users/User'
|
|||
{getSponsoredSubsAmount} = require '../../app/core/utils'
|
||||
StripeUtils = require '../lib/stripe_utils'
|
||||
moment = require 'moment'
|
||||
Product = require '../models/Product'
|
||||
|
||||
recipientCouponID = 'free'
|
||||
|
||||
# TODO: rename this to avoid collisions with 'subscriptions' variables
|
||||
subscriptions = {
|
||||
basic: {
|
||||
gems: 3500
|
||||
amount: 999 # For calculating incremental quantity before sub creation
|
||||
}
|
||||
year_sale: {
|
||||
amount: 9900
|
||||
}
|
||||
}
|
||||
|
||||
class SubscriptionHandler extends Handler
|
||||
logSubscriptionError: (user, msg) ->
|
||||
console.warn "Subscription Error: #{user.get('slug')} (#{user._id}): '#{msg}'"
|
||||
|
@ -149,51 +139,56 @@ class SubscriptionHandler extends Handler
|
|||
if err
|
||||
@logSubscriptionError(user, "Purchase year sale Stripe cancel subscription error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
metadata =
|
||||
type: req.body.type
|
||||
userID: req.user._id + ''
|
||||
gems: subscriptions.basic.gems * 12
|
||||
timestamp: parseInt(req.body.stripe?.timestamp)
|
||||
description: req.body.description
|
||||
|
||||
StripeUtils.createCharge req.user, subscriptions.year_sale.amount, metadata, (err, charge) =>
|
||||
if err
|
||||
@logSubscriptionError(req.user, "Purchase year sale create charge: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
|
||||
StripeUtils.createPayment req.user, charge, (err, payment) =>
|
||||
|
||||
Product.findOne({name: 'year_subscription'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res, 'year_subscription product not found') if not product
|
||||
|
||||
metadata =
|
||||
type: req.body.type
|
||||
userID: req.user._id + ''
|
||||
gems: product.get('gems')
|
||||
timestamp: parseInt(req.body.stripe?.timestamp)
|
||||
description: req.body.description
|
||||
|
||||
StripeUtils.createCharge req.user, product.get('amount'), metadata, (err, charge) =>
|
||||
if err
|
||||
@logSubscriptionError(req.user, "Purchase year sale create payment: #{JSON.stringify(err)}")
|
||||
@logSubscriptionError(req.user, "Purchase year sale create charge: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
|
||||
# Add terminal subscription to User with extensions for existing subscriptions
|
||||
stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
|
||||
endDate = new Date()
|
||||
if stripeSubscriptionPeriodEndDate
|
||||
endDate = stripeSubscriptionPeriodEndDate
|
||||
else if _.isString(stripeInfo.free) and new Date() < new Date(stripeInfo.free)
|
||||
endDate = new Date(stripeInfo.free)
|
||||
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
||||
stripeInfo.free = endDate.toISOString().substring(0, 10)
|
||||
req.user.set('stripe', stripeInfo)
|
||||
|
||||
# Add year's worth of gems to User
|
||||
purchased = _.clone(req.user.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += parseInt(charge.metadata.gems)
|
||||
req.user.set('purchased', purchased)
|
||||
|
||||
req.user.save (err, user) =>
|
||||
|
||||
StripeUtils.createPayment req.user, charge, (err, payment) =>
|
||||
if err
|
||||
@logSubscriptionError(req.user, "User save error: #{JSON.stringify(err)}")
|
||||
@logSubscriptionError(req.user, "Purchase year sale create payment: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
try
|
||||
msg = "Year subscription purchased by #{req.user.get('email')} #{req.user.id}"
|
||||
hipchat.sendHipChatMessage msg, ['tower']
|
||||
catch error
|
||||
@logSubscriptionError(req.user, "Year sub sale HipChat tower msg error: #{JSON.stringify(error)}")
|
||||
@sendSuccess(res, user)
|
||||
|
||||
# Add terminal subscription to User with extensions for existing subscriptions
|
||||
stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
|
||||
endDate = new Date()
|
||||
if stripeSubscriptionPeriodEndDate
|
||||
endDate = stripeSubscriptionPeriodEndDate
|
||||
else if _.isString(stripeInfo.free) and new Date() < new Date(stripeInfo.free)
|
||||
endDate = new Date(stripeInfo.free)
|
||||
endDate.setUTCFullYear(endDate.getUTCFullYear() + 1)
|
||||
stripeInfo.free = endDate.toISOString().substring(0, 10)
|
||||
req.user.set('stripe', stripeInfo)
|
||||
|
||||
# Add year's worth of gems to User
|
||||
purchased = _.clone(req.user.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += parseInt(charge.metadata.gems)
|
||||
req.user.set('purchased', purchased)
|
||||
|
||||
req.user.save (err, user) =>
|
||||
if err
|
||||
@logSubscriptionError(req.user, "User save error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
try
|
||||
msg = "Year subscription purchased by #{req.user.get('email')} #{req.user.id}"
|
||||
hipchat.sendHipChatMessage msg, ['tower']
|
||||
catch error
|
||||
@logSubscriptionError(req.user, "Year sub sale HipChat tower msg error: #{JSON.stringify(error)}")
|
||||
@sendSuccess(res, user)
|
||||
|
||||
subscribeWithPrepaidCode: (req, res) ->
|
||||
return @sendUnauthorizedError(res) unless req.user?
|
||||
|
@ -241,31 +236,35 @@ class SubscriptionHandler extends Handler
|
|||
@logSubscriptionError(user, "Redeem Prepaid Code Stripe cancel subscription error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
|
||||
# Add terminal subscription to User, extending existing subscriptions
|
||||
# TODO: refactor this into some form useable by both this and purchaseYearSale
|
||||
stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
|
||||
endDate = new moment()
|
||||
if stripeSubscriptionPeriodEndDate
|
||||
endDate = new moment(stripeSubscriptionPeriodEndDate)
|
||||
else if _.isString(stripeInfo.free) and new moment().isBefore(new moment(stripeInfo.free))
|
||||
endDate = new moment(stripeInfo.free)
|
||||
Product.findOne({name: 'basic_subscription'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res, 'basic_subscription product not found') if not product
|
||||
|
||||
endDate = endDate.add(months, 'months')
|
||||
stripeInfo.free = endDate.toISOString().substring(0, 10)
|
||||
req.user.set('stripe', stripeInfo)
|
||||
|
||||
# Add gems to User
|
||||
purchased = _.clone(req.user.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += subscriptions.basic.gems * months
|
||||
req.user.set('purchased', purchased)
|
||||
|
||||
req.user.save (err, user) =>
|
||||
if err
|
||||
@logSubscriptionError(req.user, "User save error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
@sendSuccess(res, user)
|
||||
# Add terminal subscription to User, extending existing subscriptions
|
||||
# TODO: refactor this into some form useable by both this and purchaseYearSale
|
||||
stripeInfo = _.cloneDeep(req.user.get('stripe') ? {})
|
||||
endDate = new moment()
|
||||
if stripeSubscriptionPeriodEndDate
|
||||
endDate = new moment(stripeSubscriptionPeriodEndDate)
|
||||
else if _.isString(stripeInfo.free) and new moment().isBefore(new moment(stripeInfo.free))
|
||||
endDate = new moment(stripeInfo.free)
|
||||
|
||||
endDate = endDate.add(months, 'months')
|
||||
stripeInfo.free = endDate.toISOString().substring(0, 10)
|
||||
req.user.set('stripe', stripeInfo)
|
||||
|
||||
# Add gems to User
|
||||
purchased = _.clone(req.user.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += product.get('gems') * months
|
||||
req.user.set('purchased', purchased)
|
||||
|
||||
req.user.save (err, user) =>
|
||||
if err
|
||||
@logSubscriptionError(req.user, "User save error: #{JSON.stringify(err)}")
|
||||
return @sendDatabaseError(res, err)
|
||||
@sendSuccess(res, user)
|
||||
|
||||
subscribeUser: (req, user, done) ->
|
||||
if (not req.user) or req.user.isAnonymous() or user.isAnonymous()
|
||||
|
@ -427,18 +426,22 @@ class SubscriptionHandler extends Handler
|
|||
req.body.stripe = stripeInfo
|
||||
user.set('stripe', stripeInfo)
|
||||
|
||||
if increment
|
||||
purchased = _.clone(user.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += subscriptions.basic.gems # TODO: Put actual subscription amount here
|
||||
user.set('purchased', purchased)
|
||||
Product.findOne({name: 'basic_subscription'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res, 'basic_subscription product not found') if not product
|
||||
|
||||
user.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Stripe user plan saving error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
if increment
|
||||
purchased = _.clone(user.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += product.get('gems') # TODO: Put actual subscription amount here
|
||||
user.set('purchased', purchased)
|
||||
|
||||
user.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Stripe user plan saving error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
|
||||
updateStripeRecipientSubscriptions: (req, user, customer, done) ->
|
||||
return done({res: 'Database error.', code: 500}) unless req.body.stripe?.subscribeEmails?
|
||||
|
@ -527,36 +530,40 @@ class SubscriptionHandler extends Handler
|
|||
@logSubscriptionError(user, 'User saving stripe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
createUpdateFn = (recipient, increment) =>
|
||||
(done) =>
|
||||
# Update recipient
|
||||
stripeInfo = _.cloneDeep(recipient.get('stripe') ? {})
|
||||
stripeInfo.sponsorID = user.id
|
||||
recipient.set 'stripe', stripeInfo
|
||||
if increment
|
||||
purchased = _.clone(recipient.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += subscriptions.basic.gems
|
||||
recipient.set('purchased', purchased)
|
||||
recipient.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Stripe user saving stripe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
Product.findOne({name: 'basic_subscription'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res, 'basic_subscription product not found') if not product
|
||||
|
||||
tasks = []
|
||||
for sub in stripeRecipients
|
||||
tasks.push createUpdateFn(sub.recipient, sub.increment)
|
||||
createUpdateFn = (recipient, increment) =>
|
||||
(done) =>
|
||||
# Update recipient
|
||||
stripeInfo = _.cloneDeep(recipient.get('stripe') ? {})
|
||||
stripeInfo.sponsorID = user.id
|
||||
recipient.set 'stripe', stripeInfo
|
||||
if increment
|
||||
purchased = _.clone(recipient.get('purchased'))
|
||||
purchased ?= {}
|
||||
purchased.gems ?= 0
|
||||
purchased.gems += product.get('gems')
|
||||
recipient.set('purchased', purchased)
|
||||
recipient.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Stripe user saving stripe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
|
||||
tasks = []
|
||||
for sub in stripeRecipients
|
||||
tasks.push createUpdateFn(sub.recipient, sub.increment)
|
||||
|
||||
async.parallel tasks, (err, results) =>
|
||||
return done(err) if err
|
||||
@updateStripeSponsorSubscription(req, user, customer, product, done)
|
||||
|
||||
async.parallel tasks, (err, results) =>
|
||||
return done(err) if err
|
||||
@updateStripeSponsorSubscription(req, user, customer, done)
|
||||
|
||||
updateStripeSponsorSubscription: (req, user, customer, done) ->
|
||||
updateStripeSponsorSubscription: (req, user, customer, product, done) ->
|
||||
stripeInfo = user.get('stripe') ? {}
|
||||
numSponsored = stripeInfo.recipients.length
|
||||
quantity = getSponsoredSubsAmount(subscriptions.basic.amount, numSponsored, stripeInfo.subscriptionID?)
|
||||
quantity = getSponsoredSubsAmount(product.get('amount'), numSponsored, stripeInfo.subscriptionID?)
|
||||
|
||||
findStripeSubscription customer.id, subscriptionID: stripeInfo.sponsorSubscriptionID, (subscription) =>
|
||||
if stripeInfo.sponsorSubscriptionID? and not subscription?
|
||||
|
@ -656,38 +663,42 @@ class SubscriptionHandler extends Handler
|
|||
@logSubscriptionError(user, 'Unable to find recipient subscription. ')
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
# Update recipient user
|
||||
deleteUserStripeProp(recipient, 'sponsorID')
|
||||
recipient.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Recipient user save unsubscribe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
Product.findOne({name: 'basic_subscription'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
return @sendNotFoundError(res, 'basic_subscription product not found') if not product
|
||||
|
||||
# Cancel Stripe subscription
|
||||
stripe.customers.cancelSubscription stripeInfo.customerID, sponsoredEntry.subscriptionID, (err) =>
|
||||
# Update recipient user
|
||||
deleteUserStripeProp(recipient, 'sponsorID')
|
||||
recipient.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, "Stripe cancel sponsored subscription failed. " + err)
|
||||
@logSubscriptionError(user, 'Recipient user save unsubscribe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
# Update sponsor user
|
||||
_.remove(stripeInfo.recipients, (s) -> s.userID is recipient.id)
|
||||
delete stripeInfo.unsubscribeEmail
|
||||
user.set('stripe', stripeInfo)
|
||||
req.body.stripe = stripeInfo
|
||||
user.save (err) =>
|
||||
|
||||
# Cancel Stripe subscription
|
||||
stripe.customers.cancelSubscription stripeInfo.customerID, sponsoredEntry.subscriptionID, (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Sponsor user save unsubscribe error. ' + err)
|
||||
@logSubscriptionError(user, "Stripe cancel sponsored subscription failed. " + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
|
||||
return done() unless stripeInfo.sponsorSubscriptionID?
|
||||
|
||||
# Update sponsored subscription quantity
|
||||
options =
|
||||
quantity: getSponsoredSubsAmount(subscriptions.basic.amount, stripeInfo.recipients.length, stripeInfo.subscriptionID?)
|
||||
stripe.customers.updateSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, options, (err, subscription) =>
|
||||
|
||||
# Update sponsor user
|
||||
_.remove(stripeInfo.recipients, (s) -> s.userID is recipient.id)
|
||||
delete stripeInfo.unsubscribeEmail
|
||||
user.set('stripe', stripeInfo)
|
||||
req.body.stripe = stripeInfo
|
||||
user.save (err) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Sponsored subscription quantity update error. ' + JSON.stringify(err))
|
||||
@logSubscriptionError(user, 'Sponsor user save unsubscribe error. ' + err)
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
|
||||
return done() unless stripeInfo.sponsorSubscriptionID?
|
||||
|
||||
# Update sponsored subscription quantity
|
||||
options =
|
||||
quantity: getSponsoredSubsAmount(product.get('amount'), stripeInfo.recipients.length, stripeInfo.subscriptionID?)
|
||||
stripe.customers.updateSubscription stripeInfo.customerID, stripeInfo.sponsorSubscriptionID, options, (err, subscription) =>
|
||||
if err
|
||||
@logSubscriptionError(user, 'Sponsored subscription quantity update error. ' + JSON.stringify(err))
|
||||
return done({res: 'Database error.', code: 500})
|
||||
done()
|
||||
|
||||
module.exports = new SubscriptionHandler()
|
||||
|
|
|
@ -6,6 +6,7 @@ User = require '../users/User'
|
|||
StripeUtils = require '../lib/stripe_utils'
|
||||
utils = require '../../app/core/utils'
|
||||
mongoose = require 'mongoose'
|
||||
Product = require '../models/Product'
|
||||
|
||||
# TODO: Should this happen on a save() call instead of a prepaid/-/create post?
|
||||
# TODO: Probably a better way to create a unique 8 charactor string property using db voodoo
|
||||
|
@ -17,8 +18,6 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
jsonSchema: require '../../app/schemas/models/prepaid.schema'
|
||||
allowedMethods: ['GET','POST']
|
||||
|
||||
baseAmount: 999
|
||||
|
||||
logError: (user, msg) ->
|
||||
console.warn "Prepaid Error: [#{user.get('slug')} (#{user._id})] '#{msg}'"
|
||||
|
||||
|
@ -134,9 +133,13 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
return @sendBadInputError(res) unless isNaN(months) is false and months > 0
|
||||
return @sendError(res, 403, "Users or Months must be greater than 3") if maxRedeemers < 3 and months < 3
|
||||
|
||||
@purchasePrepaidTerminalSubscription req.user, description, maxRedeemers, months, timestamp, token, (err, prepaid) =>
|
||||
Product.findOne({name: 'prepaid_subscription'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
return @sendNotFoundError(res, 'prepaid_subscription product not found') if not product
|
||||
|
||||
@purchasePrepaidTerminalSubscription req.user, description, maxRedeemers, months, timestamp, token, product, (err, prepaid) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
|
||||
else if req.body.type is 'course'
|
||||
maxRedeemers = parseInt(req.body.maxRedeemers)
|
||||
|
@ -145,18 +148,22 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
|
||||
return @sendBadInputError(res) unless isNaN(maxRedeemers) is false and maxRedeemers > 0
|
||||
|
||||
@purchasePrepaidCourse req.user, maxRedeemers, timestamp, token, (err, prepaid) =>
|
||||
# TODO: this badinput detection is fragile, in course instance handler as well
|
||||
return @sendBadInputError(res, err) if err is 'Missing required Stripe token'
|
||||
Product.findOne({name: 'course'}).exec (err, product) =>
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
return @sendNotFoundError(res, 'course product not found') if not product
|
||||
|
||||
@purchasePrepaidCourse req.user, maxRedeemers, timestamp, token, product, (err, prepaid) =>
|
||||
# TODO: this badinput detection is fragile, in course instance handler as well
|
||||
return @sendBadInputError(res, err) if err is 'Missing required Stripe token'
|
||||
return @sendDatabaseError(res, err) if err
|
||||
@sendSuccess(res, prepaid.toObject())
|
||||
else
|
||||
@sendForbiddenError(res)
|
||||
|
||||
purchasePrepaidCourse: (user, maxRedeemers, timestamp, token, done) ->
|
||||
purchasePrepaidCourse: (user, maxRedeemers, timestamp, token, product, done) ->
|
||||
type = 'course'
|
||||
|
||||
amount = maxRedeemers * 400
|
||||
amount = maxRedeemers * product.get('amount')
|
||||
if amount > 0 and not (token or user.isAdmin())
|
||||
@logError(user, "Purchase prepaid courses missing required Stripe token #{amount}")
|
||||
return done('Missing required Stripe token')
|
||||
|
@ -190,7 +197,7 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
hipchat.sendHipChatMessage msg, ['tower']
|
||||
@createPrepaid(user, type, maxRedeemers, {}, done)
|
||||
|
||||
purchasePrepaidTerminalSubscription: (user, description, maxRedeemers, months, timestamp, token, done) ->
|
||||
purchasePrepaidTerminalSubscription: (user, description, maxRedeemers, months, timestamp, token, product, done) ->
|
||||
type = 'terminal_subscription'
|
||||
|
||||
StripeUtils.getCustomer user, token, (err, customer) =>
|
||||
|
@ -207,7 +214,7 @@ PrepaidHandler = class PrepaidHandler extends Handler
|
|||
months: months
|
||||
productID: "prepaid #{type}"
|
||||
|
||||
amount = utils.getPrepaidCodeAmount(@baseAmount, maxRedeemers, months)
|
||||
amount = utils.getPrepaidCodeAmount(product.get('amount'), maxRedeemers, months)
|
||||
|
||||
StripeUtils.createCharge user, amount, metadata, (err, charge) =>
|
||||
if err
|
||||
|
|
|
@ -3,6 +3,7 @@ async = require 'async'
|
|||
errors = require '../../commons/errors'
|
||||
scoringUtils = require './scoringUtils'
|
||||
LevelSession = require '../../levels/sessions/LevelSession'
|
||||
Mandate = require '../../models/Mandate'
|
||||
|
||||
module.exports = getTwoGames = (req, res) ->
|
||||
#return errors.unauthorized(res, 'You need to be logged in to get games.') unless req.user?.get('email')
|
||||
|
@ -10,11 +11,15 @@ module.exports = getTwoGames = (req, res) ->
|
|||
humansSessionID = req.body.humansGameID
|
||||
ogresSessionID = req.body.ogresGameID
|
||||
return getSpecificSessions res, humansSessionID, ogresSessionID if humansSessionID and ogresSessionID
|
||||
options =
|
||||
background: req.body.background
|
||||
levelID: req.body.levelID
|
||||
leagueID: req.body.leagueID
|
||||
getRandomSessions req.user, options, sendSessionsResponse(res)
|
||||
Mandate.findOne({}).cache(5 * 60 * 1000).exec (err, mandate) ->
|
||||
if err then return errors.serverError res, "Error fetching our Mandate: #{err}"
|
||||
if (throughputRatio = mandate?.get 'simulationThroughputRatio')? and Math.random() > throughputRatio
|
||||
return sendSessionsResponse(res)(null, [])
|
||||
options =
|
||||
background: req.body.background
|
||||
levelID: req.body.levelID
|
||||
leagueID: req.body.leagueID
|
||||
getRandomSessions req.user, options, sendSessionsResponse(res)
|
||||
|
||||
sessionSelectionString = 'team totalScore transpiledCode submittedCodeLanguage teamSpells levelID creatorName creator submitDate leagues'
|
||||
|
||||
|
@ -22,7 +27,6 @@ sendSessionsResponse = (res) ->
|
|||
(err, sessions) ->
|
||||
if err then return errors.serverError res, "Couldn't get two games to simulate: #{err}"
|
||||
unless _.filter(sessions).length is 2
|
||||
console.log 'No games to score.', sessions.length
|
||||
res.send 204, 'No games to score.'
|
||||
return res.end()
|
||||
taskObject = messageGenerated: Date.now(), sessions: (scoringUtils.formatSessionInformation session for session in sessions)
|
||||
|
|
79
server/routes/db/product.coffee
Normal file
|
@ -0,0 +1,79 @@
|
|||
Product = require '../../models/Product'
|
||||
errors = require '../../commons/errors'
|
||||
config = require '../../../server_config'
|
||||
|
||||
module.exports.get = (req, res) ->
|
||||
|
||||
Product.find().lean().exec (err, products) ->
|
||||
return errors.serverError(res) if err
|
||||
names = (product.name for product in products)
|
||||
unless config.isProduction
|
||||
for product in initProducts
|
||||
if not _.contains(names, product.name)
|
||||
# upsert products in initProducts if they DNE
|
||||
products.push(product)
|
||||
new Product(product).save _.noop
|
||||
res.send(products)
|
||||
|
||||
###
|
||||
Stub data, used in tests and dev environment.
|
||||
|
||||
These values are only upserted when the test/dev db does not already contain them.
|
||||
If you are testing products and need to change them, you'll need to edit the db values directly.
|
||||
###
|
||||
|
||||
|
||||
initProducts = [
|
||||
{
|
||||
name: 'gems_5'
|
||||
amount: 100
|
||||
gems: 5000
|
||||
priceString: '$1.00'
|
||||
i18n: 'buy_gems.few_gems'
|
||||
}
|
||||
|
||||
{
|
||||
name: 'gems_10'
|
||||
amount: 101
|
||||
gems: 11000
|
||||
priceString: '$1.01'
|
||||
i18n: 'buy_gems.pile_gems'
|
||||
}
|
||||
|
||||
{
|
||||
name: 'gems_20'
|
||||
amount: 102
|
||||
gems: 25000
|
||||
priceString: '$1.02'
|
||||
i18n: 'buy_gems.chest_gems'
|
||||
}
|
||||
|
||||
{
|
||||
name: 'custom'
|
||||
type: 'purchase'
|
||||
}
|
||||
|
||||
{
|
||||
name: 'basic_subscription'
|
||||
amount: 100
|
||||
gems: 3500
|
||||
planID: 'basic'
|
||||
}
|
||||
|
||||
{
|
||||
name: 'year_subscription'
|
||||
amount: 1000
|
||||
gems: 42000
|
||||
}
|
||||
|
||||
{
|
||||
name: 'prepaid_subscription'
|
||||
amount: 100
|
||||
gems: 3500
|
||||
}
|
||||
|
||||
{
|
||||
name: 'course'
|
||||
amount: 100
|
||||
}
|
||||
]
|
2
server/routes/index.coffee
Normal file
|
@ -0,0 +1,2 @@
|
|||
module.exports.setup = (app) ->
|
||||
app.get('/db/products', require('./db/product').get)
|
|
@ -14,6 +14,7 @@ user = require './server/users/user_handler'
|
|||
logging = require './server/commons/logging'
|
||||
config = require './server_config'
|
||||
auth = require './server/routes/auth'
|
||||
routes = require './server/routes'
|
||||
UserHandler = require './server/users/user_handler'
|
||||
hipchat = require './server/hipchat'
|
||||
global.tv4 = require 'tv4' # required for TreemaUtils to work
|
||||
|
@ -29,6 +30,7 @@ productionLogging = (tokens, req, res) ->
|
|||
else if status >= 300 then color = 36
|
||||
elapsed = (new Date()) - req._startTime
|
||||
elapsedColor = if elapsed < 500 then 90 else 31
|
||||
return null if status is 404 and /\/feedback/.test req.originalUrl # We know that these usually 404 by design (bad design?)
|
||||
if (status isnt 200 and status isnt 201 and status isnt 204 and status isnt 304 and status isnt 302) or elapsed > 500
|
||||
return "\x1b[90m#{req.method} #{req.originalUrl} \x1b[#{color}m#{res.statusCode} \x1b[#{elapsedColor}m#{elapsed}ms\x1b[0m"
|
||||
null
|
||||
|
@ -166,6 +168,7 @@ setupFacebookCrossDomainCommunicationRoute = (app) ->
|
|||
res.sendfile path.join(__dirname, 'public', 'channel.html')
|
||||
|
||||
exports.setupRoutes = (app) ->
|
||||
routes.setup(app)
|
||||
app.use app.router
|
||||
|
||||
baseRoute.setup app
|
||||
|
|
148
spec/fixtures/db-discount-handler-test-6.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCUnKaReE7xLUdVx6ixF1h",
|
||||
"id": "tok_17IOOlKaReE7xLUdF9cOZScg",
|
||||
"card": {
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuNWxO5eWsQG",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5",
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -43,55 +43,159 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG/subscriptions",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG/subscriptions/sub_7VCuZWrSt0bF8c",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP/subscriptions/sub_7XTLVSO3Guyty9",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
|
48
spec/fixtures/db-discount-handler-test-7.json
vendored
|
@ -11,10 +11,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuNWxO5eWsQG",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -22,7 +22,7 @@
|
|||
"coupon": {
|
||||
"id": "20pct"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
|
@ -31,8 +31,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5",
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -40,24 +40,24 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -69,10 +69,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuNWxO5eWsQG",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -80,7 +80,7 @@
|
|||
"coupon": {
|
||||
"id": "20pct"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
|
@ -89,8 +89,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5",
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -98,24 +98,24 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
|
24
spec/fixtures/db-discount-handler-test-8.json
vendored
|
@ -2,17 +2,17 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "DELETE",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG/discount",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP/discount",
|
||||
"status": 200,
|
||||
"response": {}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuNWxO5eWsQG",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -23,8 +23,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5",
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -32,24 +32,24 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
|
48
spec/fixtures/db-discount-handler-test-9.json
vendored
|
@ -11,10 +11,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuNWxO5eWsQG",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -22,7 +22,7 @@
|
|||
"coupon": {
|
||||
"id": "20pct"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
|
@ -31,8 +31,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5",
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -40,24 +40,24 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -69,10 +69,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCuNWxO5eWsQG",
|
||||
"path": "/v1/customers/cus_7XTLw21mDCPduP",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuNWxO5eWsQG",
|
||||
"id": "cus_7XTLw21mDCPduP",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -80,7 +80,7 @@
|
|||
"coupon": {
|
||||
"id": "20pct"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
|
@ -89,8 +89,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUnKaReE7xLUdZ8FpRcR5",
|
||||
"customer": "cus_7VCuNWxO5eWsQG"
|
||||
"id": "card_17IOOlKaReE7xLUdwvPnfV15",
|
||||
"customer": "cus_7XTLw21mDCPduP"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -98,24 +98,24 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCuZWrSt0bF8c",
|
||||
"id": "sub_7XTLVSO3Guyty9",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363418,
|
||||
"current_period_start": 1449685018,
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"current_period_end": 1452885828,
|
||||
"current_period_start": 1450207428,
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"discount": {
|
||||
"coupon": {
|
||||
"id": "500off"
|
||||
},
|
||||
"customer": "cus_7VCuNWxO5eWsQG",
|
||||
"subscription": "sub_7VCuZWrSt0bF8c"
|
||||
"customer": "cus_7XTLw21mDCPduP",
|
||||
"subscription": "sub_7XTLVSO3Guyty9"
|
||||
},
|
||||
"metadata": {
|
||||
"id": "00000000000000000000005d"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVJKaReE7xLUdzpXOGZ9v",
|
||||
"id": "tok_17IOPOKaReE7xLUdfaGNs2bY",
|
||||
"card": {
|
||||
"id": "card_17GCVJKaReE7xLUdKOWpllRX"
|
||||
"id": "card_17IOPOKaReE7xLUdynADA8zk"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvE20H99SoVJ",
|
||||
"id": "cus_7XTMkthRYmfilo",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVJKaReE7xLUdKOWpllRX",
|
||||
"customer": "cus_7VCvE20H99SoVJ"
|
||||
"id": "card_17IOPOKaReE7xLUdynADA8zk",
|
||||
"customer": "cus_7XTMkthRYmfilo"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -52,10 +52,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvE20H99SoVJ",
|
||||
"path": "/v1/customers/cus_7XTMkthRYmfilo",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvE20H99SoVJ",
|
||||
"id": "cus_7XTMkthRYmfilo",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -66,8 +66,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVJKaReE7xLUdKOWpllRX",
|
||||
"customer": "cus_7VCvE20H99SoVJ"
|
||||
"id": "card_17IOPOKaReE7xLUdynADA8zk",
|
||||
"customer": "cus_7XTMkthRYmfilo"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -83,21 +83,21 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVLKaReE7xLUdb9DcZ4om",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCvE20H99SoVJ",
|
||||
"id": "ch_17IOPQKaReE7xLUdsAmwl7fg",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTMkthRYmfilo",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685049575"
|
||||
"timestamp": "1450207466249"
|
||||
},
|
||||
"paid": true,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVJKaReE7xLUdKOWpllRX",
|
||||
"customer": "cus_7VCvE20H99SoVJ"
|
||||
"id": "card_17IOPOKaReE7xLUdynADA8zk",
|
||||
"customer": "cus_7XTMkthRYmfilo"
|
||||
}
|
||||
}
|
||||
},
|
||||
|
@ -109,21 +109,21 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCVLKaReE7xLUdb9DcZ4om",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCvE20H99SoVJ",
|
||||
"id": "ch_17IOPQKaReE7xLUdsAmwl7fg",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTMkthRYmfilo",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685049575"
|
||||
"timestamp": "1450207466249"
|
||||
},
|
||||
"paid": true,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVJKaReE7xLUdKOWpllRX",
|
||||
"customer": "cus_7VCvE20H99SoVJ"
|
||||
"id": "card_17IOPOKaReE7xLUdynADA8zk",
|
||||
"customer": "cus_7XTMkthRYmfilo"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVNKaReE7xLUd2tmSQ1KH",
|
||||
"id": "tok_17IOPSKaReE7xLUdyZv4jUA6",
|
||||
"card": {
|
||||
"id": "card_17GCVMKaReE7xLUdZVTFHMmq"
|
||||
"id": "card_17IOPSKaReE7xLUdOOKz1MOG"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvZ7KBrJ8csQ",
|
||||
"id": "cus_7XTMBOnMy9jbYM",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVMKaReE7xLUdZVTFHMmq",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPSKaReE7xLUdOOKz1MOG",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -52,10 +52,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvZ7KBrJ8csQ",
|
||||
"path": "/v1/customers/cus_7XTMBOnMy9jbYM",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvZ7KBrJ8csQ",
|
||||
"id": "cus_7XTMBOnMy9jbYM",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -66,8 +66,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVMKaReE7xLUdZVTFHMmq",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPSKaReE7xLUdOOKz1MOG",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -83,9 +83,9 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVOKaReE7xLUd1ZQVMJKB",
|
||||
"id": "ch_17IOPUKaReE7xLUd1gLXrdte",
|
||||
"amount": 5000,
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ",
|
||||
"customer": "cus_7XTMBOnMy9jbYM",
|
||||
"metadata": {
|
||||
"productID": "custom",
|
||||
"timestamp": "1447445242091",
|
||||
|
@ -96,8 +96,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVMKaReE7xLUdZVTFHMmq",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPSKaReE7xLUdOOKz1MOG",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVPKaReE7xLUdJcZimvbF",
|
||||
"id": "tok_17IOPVKaReE7xLUdJAvZ79Fe",
|
||||
"card": {
|
||||
"id": "card_17GCVPKaReE7xLUdRwBCjoW4"
|
||||
"id": "card_17IOPVKaReE7xLUdhslZrW4t"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvZ7KBrJ8csQ",
|
||||
"path": "/v1/customers/cus_7XTMBOnMy9jbYM",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvZ7KBrJ8csQ",
|
||||
"id": "cus_7XTMBOnMy9jbYM",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVPKaReE7xLUdRwBCjoW4",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPVKaReE7xLUdhslZrW4t",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -48,9 +48,9 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCVOKaReE7xLUd1ZQVMJKB",
|
||||
"id": "ch_17IOPUKaReE7xLUd1gLXrdte",
|
||||
"amount": 5000,
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ",
|
||||
"customer": "cus_7XTMBOnMy9jbYM",
|
||||
"metadata": {
|
||||
"productID": "custom",
|
||||
"timestamp": "1447445242091",
|
||||
|
@ -61,8 +61,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVMKaReE7xLUdZVTFHMmq",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPSKaReE7xLUdOOKz1MOG",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -75,9 +75,9 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVSKaReE7xLUdd5E7dowz",
|
||||
"id": "ch_17IOPXKaReE7xLUdEinedgz6",
|
||||
"amount": 73000,
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ",
|
||||
"customer": "cus_7XTMBOnMy9jbYM",
|
||||
"metadata": {
|
||||
"productID": "custom",
|
||||
"timestamp": "1447445242092"
|
||||
|
@ -87,8 +87,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVPKaReE7xLUdRwBCjoW4",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPVKaReE7xLUdhslZrW4t",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVTKaReE7xLUdOnqynJY7",
|
||||
"id": "tok_17IOPYKaReE7xLUdSnJV6x8N",
|
||||
"card": {
|
||||
"id": "card_17GCVSKaReE7xLUdjh0HgmFn"
|
||||
"id": "card_17IOPYKaReE7xLUdXqbKgSlb"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -15,10 +15,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvZ7KBrJ8csQ",
|
||||
"path": "/v1/customers/cus_7XTMBOnMy9jbYM",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvZ7KBrJ8csQ",
|
||||
"id": "cus_7XTMBOnMy9jbYM",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVSKaReE7xLUdjh0HgmFn",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPYKaReE7xLUdXqbKgSlb",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -48,9 +48,9 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCVSKaReE7xLUdd5E7dowz",
|
||||
"id": "ch_17IOPXKaReE7xLUdEinedgz6",
|
||||
"amount": 73000,
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ",
|
||||
"customer": "cus_7XTMBOnMy9jbYM",
|
||||
"metadata": {
|
||||
"productID": "custom",
|
||||
"timestamp": "1447445242092"
|
||||
|
@ -60,14 +60,14 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVPKaReE7xLUdRwBCjoW4",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPVKaReE7xLUdhslZrW4t",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCVOKaReE7xLUd1ZQVMJKB",
|
||||
"id": "ch_17IOPUKaReE7xLUd1gLXrdte",
|
||||
"amount": 5000,
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ",
|
||||
"customer": "cus_7XTMBOnMy9jbYM",
|
||||
"metadata": {
|
||||
"productID": "custom",
|
||||
"timestamp": "1447445242091",
|
||||
|
@ -78,8 +78,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVMKaReE7xLUdZVTFHMmq",
|
||||
"customer": "cus_7VCvZ7KBrJ8csQ"
|
||||
"id": "card_17IOPSKaReE7xLUdOOKz1MOG",
|
||||
"customer": "cus_7XTMBOnMy9jbYM"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
28
spec/fixtures/db-payment-stripe-test-01.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCUvKaReE7xLUdo7q79Zbp",
|
||||
"id": "tok_17IOOxKaReE7xLUdajQLXj2u",
|
||||
"card": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCubHuvGFt4nH",
|
||||
"id": "cus_7XTLZvrxxi9h67",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -52,10 +52,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCubHuvGFt4nH",
|
||||
"path": "/v1/customers/cus_7XTLZvrxxi9h67",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCubHuvGFt4nH",
|
||||
"id": "cus_7XTLZvrxxi9h67",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -66,8 +66,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -83,9 +83,9 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCUxKaReE7xLUddy1fN9Nl",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOOyKaReE7xLUdzY39hxln",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -96,8 +96,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
12
spec/fixtures/db-payment-stripe-test-02.json
vendored
|
@ -2,7 +2,7 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCubHuvGFt4nH",
|
||||
"path": "/v1/customers/cus_7XTLZvrxxi9h67",
|
||||
"status": 400,
|
||||
"response": {
|
||||
"error": {
|
||||
|
@ -18,9 +18,9 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCUxKaReE7xLUddy1fN9Nl",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOOyKaReE7xLUdzY39hxln",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -31,8 +31,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
22
spec/fixtures/db-payment-stripe-test-03.json
vendored
|
@ -7,9 +7,9 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCUxKaReE7xLUddy1fN9Nl",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOOyKaReE7xLUdzY39hxln",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -20,8 +20,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -34,21 +34,21 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCUzKaReE7xLUdviRu5P6Z",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOP1KaReE7xLUdLHaawQjF",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685028592"
|
||||
"timestamp": "1450207442600"
|
||||
},
|
||||
"paid": true,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
62
spec/fixtures/db-payment-stripe-test-04.json
vendored
|
@ -2,10 +2,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCubHuvGFt4nH",
|
||||
"path": "/v1/customers/cus_7XTLZvrxxi9h67",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCubHuvGFt4nH",
|
||||
"id": "cus_7XTLZvrxxi9h67",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -16,8 +16,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -33,9 +33,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCV0KaReE7xLUd6riHo5io",
|
||||
"id": "tok_17IOP2KaReE7xLUdxvu0xWNX",
|
||||
"card": {
|
||||
"id": "card_17GCV0KaReE7xLUdA7hdLMnV"
|
||||
"id": "card_17IOP2KaReE7xLUdgHcD4Uj5"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -43,10 +43,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCubHuvGFt4nH",
|
||||
"path": "/v1/customers/cus_7XTLZvrxxi9h67",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCubHuvGFt4nH",
|
||||
"id": "cus_7XTLZvrxxi9h67",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -57,8 +57,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCV0KaReE7xLUdA7hdLMnV",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOP2KaReE7xLUdgHcD4Uj5",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -76,27 +76,27 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCUzKaReE7xLUdviRu5P6Z",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOP1KaReE7xLUdLHaawQjF",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685028592"
|
||||
"timestamp": "1450207442600"
|
||||
},
|
||||
"paid": true,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCUxKaReE7xLUddy1fN9Nl",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOOyKaReE7xLUdzY39hxln",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -107,8 +107,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCUvKaReE7xLUdBp1HF9sT",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOOxKaReE7xLUdaA1sZ1RB",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -121,31 +121,31 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCV2KaReE7xLUdffVpUhFO",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCubHuvGFt4nH",
|
||||
"id": "ch_17IOP4KaReE7xLUdLWQ28NtO",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLZvrxxi9h67",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685031026"
|
||||
"timestamp": "1450207444904"
|
||||
},
|
||||
"paid": true,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV0KaReE7xLUdA7hdLMnV",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOP2KaReE7xLUdgHcD4Uj5",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCubHuvGFt4nH",
|
||||
"path": "/v1/customers/cus_7XTLZvrxxi9h67",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCubHuvGFt4nH",
|
||||
"id": "cus_7XTLZvrxxi9h67",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -156,8 +156,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCV0KaReE7xLUdA7hdLMnV",
|
||||
"customer": "cus_7VCubHuvGFt4nH"
|
||||
"id": "card_17IOP2KaReE7xLUdgHcD4Uj5",
|
||||
"customer": "cus_7XTLZvrxxi9h67"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
|
50
spec/fixtures/db-payment-stripe-test-05.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCV3KaReE7xLUdLcKedDEd",
|
||||
"id": "tok_17IOP6KaReE7xLUdyel0tJtw",
|
||||
"card": {
|
||||
"id": "card_17GCV3KaReE7xLUdFUXfU85r"
|
||||
"id": "card_17IOP6KaReE7xLUdvj1C0uY3"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuAQ6nYInY8z",
|
||||
"id": "cus_7XTLwWj4NCwj2S",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCV3KaReE7xLUdFUXfU85r",
|
||||
"customer": "cus_7VCuAQ6nYInY8z"
|
||||
"id": "card_17IOP6KaReE7xLUdvj1C0uY3",
|
||||
"customer": "cus_7XTLwWj4NCwj2S"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -52,10 +52,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuAQ6nYInY8z",
|
||||
"path": "/v1/customers/cus_7XTLwWj4NCwj2S",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuAQ6nYInY8z",
|
||||
"id": "cus_7XTLwWj4NCwj2S",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -66,8 +66,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCV3KaReE7xLUdFUXfU85r",
|
||||
"customer": "cus_7VCuAQ6nYInY8z"
|
||||
"id": "card_17IOP6KaReE7xLUdvj1C0uY3",
|
||||
"customer": "cus_7XTLwWj4NCwj2S"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -83,9 +83,9 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCV5KaReE7xLUd0amzDJs7",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuAQ6nYInY8z",
|
||||
"id": "ch_17IOP7KaReE7xLUdDnFZwMu7",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLwWj4NCwj2S",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -96,15 +96,15 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV3KaReE7xLUdFUXfU85r",
|
||||
"customer": "cus_7VCuAQ6nYInY8z"
|
||||
"id": "card_17IOP6KaReE7xLUdvj1C0uY3",
|
||||
"customer": "cus_7XTLwWj4NCwj2S"
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuAQ6nYInY8z",
|
||||
"path": "/v1/customers/cus_7XTLwWj4NCwj2S",
|
||||
"status": 400,
|
||||
"response": {
|
||||
"error": {
|
||||
|
@ -120,9 +120,9 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCV5KaReE7xLUd0amzDJs7",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuAQ6nYInY8z",
|
||||
"id": "ch_17IOP7KaReE7xLUdDnFZwMu7",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLwWj4NCwj2S",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -133,8 +133,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV3KaReE7xLUdFUXfU85r",
|
||||
"customer": "cus_7VCuAQ6nYInY8z"
|
||||
"id": "card_17IOP6KaReE7xLUdvj1C0uY3",
|
||||
"customer": "cus_7XTLwWj4NCwj2S"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
@ -147,9 +147,9 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCV6KaReE7xLUdiTvUGa07",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuAQ6nYInY8z",
|
||||
"id": "ch_17IOP9KaReE7xLUdEyubPCWU",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTLwWj4NCwj2S",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
|
@ -160,8 +160,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV3KaReE7xLUdFUXfU85r",
|
||||
"customer": "cus_7VCuAQ6nYInY8z"
|
||||
"id": "card_17IOP6KaReE7xLUdvj1C0uY3",
|
||||
"customer": "cus_7XTLwWj4NCwj2S"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
18
spec/fixtures/db-payment-stripe-test-06.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCV7KaReE7xLUd3gnnjv7x",
|
||||
"id": "tok_17IOPAKaReE7xLUdrPE253ea",
|
||||
"card": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuzP303kt1eU",
|
||||
"id": "cus_7XTL5uSTRsbBAg",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -52,10 +52,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuzP303kt1eU",
|
||||
"path": "/v1/customers/cus_7XTL5uSTRsbBAg",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCuzP303kt1eU",
|
||||
"id": "cus_7XTL5uSTRsbBAg",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -66,8 +66,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
|
18
spec/fixtures/db-payment-stripe-test-07.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCV9KaReE7xLUdelU9sCaA",
|
||||
"id": "tok_17IOPDKaReE7xLUdOTkDGNQH",
|
||||
"card": {
|
||||
"id": "card_17GCV9KaReE7xLUd5uODONlo"
|
||||
"id": "card_17IOPDKaReE7xLUdOPYVzwbP"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuzP303kt1eU",
|
||||
"path": "/v1/customers/cus_7XTL5uSTRsbBAg",
|
||||
"status": 402,
|
||||
"response": {
|
||||
"error": {
|
||||
|
@ -31,21 +31,21 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCV9KaReE7xLUduvVirhN5",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPCKaReE7xLUdjfj5TqZH",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685037831"
|
||||
"timestamp": "1450207452790"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
30
spec/fixtures/db-payment-stripe-test-08.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVCKaReE7xLUdWbFQacYN",
|
||||
"id": "tok_17IOPFKaReE7xLUdEKcEw4rn",
|
||||
"card": {
|
||||
"id": "card_17GCVCKaReE7xLUdjoXBJKqC"
|
||||
"id": "card_17IOPFKaReE7xLUdIsElfCWI"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuzP303kt1eU",
|
||||
"path": "/v1/customers/cus_7XTL5uSTRsbBAg",
|
||||
"status": 402,
|
||||
"response": {
|
||||
"error": {
|
||||
|
@ -31,39 +31,39 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCVBKaReE7xLUduQybm6xT",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPFKaReE7xLUdToSxLUhB",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685040285"
|
||||
"timestamp": "1450207455401"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCV9KaReE7xLUduvVirhN5",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPCKaReE7xLUdjfj5TqZH",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685037831"
|
||||
"timestamp": "1450207452790"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
42
spec/fixtures/db-payment-stripe-test-09.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVEKaReE7xLUdByVccSzA",
|
||||
"id": "tok_17IOPIKaReE7xLUdohRtii5V",
|
||||
"card": {
|
||||
"id": "card_17GCVEKaReE7xLUdRUCeIUtP"
|
||||
"id": "card_17IOPIKaReE7xLUdQ34s7FHR"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuzP303kt1eU",
|
||||
"path": "/v1/customers/cus_7XTL5uSTRsbBAg",
|
||||
"status": 402,
|
||||
"response": {
|
||||
"error": {
|
||||
|
@ -31,57 +31,57 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCVDKaReE7xLUdyZAPbXCM",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPIKaReE7xLUdReuRmdCl",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685042746"
|
||||
"timestamp": "1450207457940"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCVBKaReE7xLUduQybm6xT",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPFKaReE7xLUdToSxLUhB",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685040285"
|
||||
"timestamp": "1450207455401"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCV9KaReE7xLUduvVirhN5",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPCKaReE7xLUdjfj5TqZH",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685037831"
|
||||
"timestamp": "1450207452790"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
54
spec/fixtures/db-payment-stripe-test-10.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVHKaReE7xLUdB9odSMB6",
|
||||
"id": "tok_17IOPLKaReE7xLUdiOrt8XEg",
|
||||
"card": {
|
||||
"id": "card_17GCVHKaReE7xLUdAYwa1Wkj"
|
||||
"id": "card_17IOPLKaReE7xLUdUtDdouiy"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -15,7 +15,7 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCuzP303kt1eU",
|
||||
"path": "/v1/customers/cus_7XTL5uSTRsbBAg",
|
||||
"status": 402,
|
||||
"response": {
|
||||
"error": {
|
||||
|
@ -31,75 +31,75 @@
|
|||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "ch_17GCVGKaReE7xLUdu3HU9wB5",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPKKaReE7xLUdGocBlrbj",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685044928"
|
||||
"timestamp": "1450207460901"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCVDKaReE7xLUdyZAPbXCM",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPIKaReE7xLUdReuRmdCl",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685042746"
|
||||
"timestamp": "1450207457940"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCVBKaReE7xLUduQybm6xT",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPFKaReE7xLUdToSxLUhB",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685040285"
|
||||
"timestamp": "1450207455401"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "ch_17GCV9KaReE7xLUduvVirhN5",
|
||||
"amount": 499,
|
||||
"customer": "cus_7VCuzP303kt1eU",
|
||||
"id": "ch_17IOPCKaReE7xLUdjfj5TqZH",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTL5uSTRsbBAg",
|
||||
"metadata": {
|
||||
"productID": "gems_5",
|
||||
"gems": "5000",
|
||||
"timestamp": "1449685037831"
|
||||
"timestamp": "1450207452790"
|
||||
},
|
||||
"paid": false,
|
||||
"refunds": {
|
||||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCV7KaReE7xLUdiPjgEUMd",
|
||||
"customer": "cus_7VCuzP303kt1eU"
|
||||
"id": "card_17IOPAKaReE7xLUdbLiixDCY",
|
||||
"customer": "cus_7XTL5uSTRsbBAg"
|
||||
}
|
||||
}
|
||||
],
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVVKaReE7xLUd9mYY9N7i",
|
||||
"id": "tok_17IOPcKaReE7xLUd21HNj8Lx",
|
||||
"card": {
|
||||
"id": "card_17GCVVKaReE7xLUdlhNMXbGd"
|
||||
"id": "card_17IOPcKaReE7xLUdk4xzxjp3"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVVKaReE7xLUdNnWusa8M",
|
||||
"id": "tok_17IOPdKaReE7xLUdTLUKnG0J",
|
||||
"card": {
|
||||
"id": "card_17GCVVKaReE7xLUdNzakl6za"
|
||||
"id": "card_17IOPdKaReE7xLUds6oneFJM"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvt7iNlagXQA",
|
||||
"id": "cus_7XTMzZwqOZpLXW",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVVKaReE7xLUdNzakl6za",
|
||||
"customer": "cus_7VCvt7iNlagXQA"
|
||||
"id": "card_17IOPdKaReE7xLUds6oneFJM",
|
||||
"customer": "cus_7XTMzZwqOZpLXW"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -43,10 +43,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvt7iNlagXQA",
|
||||
"path": "/v1/customers/cus_7XTMzZwqOZpLXW",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvt7iNlagXQA",
|
||||
"id": "cus_7XTMzZwqOZpLXW",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -57,8 +57,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVVKaReE7xLUdNzakl6za",
|
||||
"customer": "cus_7VCvt7iNlagXQA"
|
||||
"id": "card_17IOPdKaReE7xLUds6oneFJM",
|
||||
"customer": "cus_7XTMzZwqOZpLXW"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -74,12 +74,12 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVWKaReE7xLUdZLmqWCt6",
|
||||
"amount": 400,
|
||||
"customer": "cus_7VCvt7iNlagXQA",
|
||||
"id": "ch_17IOPeKaReE7xLUd3o8mN5yw",
|
||||
"amount": 100,
|
||||
"customer": "cus_7XTMzZwqOZpLXW",
|
||||
"metadata": {
|
||||
"type": "course",
|
||||
"timestamp": "1449685061856",
|
||||
"timestamp": "1450207481311",
|
||||
"productID": "prepaid course"
|
||||
},
|
||||
"paid": true,
|
||||
|
@ -87,8 +87,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVVKaReE7xLUdNzakl6za",
|
||||
"customer": "cus_7VCvt7iNlagXQA"
|
||||
"id": "card_17IOPdKaReE7xLUds6oneFJM",
|
||||
"customer": "cus_7XTMzZwqOZpLXW"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVXKaReE7xLUdOVrQZisx",
|
||||
"id": "tok_17IOQgKaReE7xLUd7Cj6SMxq",
|
||||
"card": {
|
||||
"id": "card_17GCVXKaReE7xLUdFEluXOeu"
|
||||
"id": "card_17IOQgKaReE7xLUd2XI9u2el"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvUi50nXhjWn",
|
||||
"id": "cus_7XTN61mUy646vB",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,36 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVXKaReE7xLUdFEluXOeu",
|
||||
"customer": "cus_7VCvUi50nXhjWn"
|
||||
"id": "card_17IOQgKaReE7xLUd2XI9u2el",
|
||||
"customer": "cus_7XTN61mUy646vB"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7XTN61mUy646vB",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7XTN61mUy646vB",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "user89@me.com",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000081"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17IOQgKaReE7xLUd2XI9u2el",
|
||||
"customer": "cus_7XTN61mUy646vB"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -46,12 +74,12 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVYKaReE7xLUdstf63Kol",
|
||||
"amount": 1200,
|
||||
"customer": "cus_7VCvUi50nXhjWn",
|
||||
"id": "ch_17IOQhKaReE7xLUd4dyiqDny",
|
||||
"amount": 300,
|
||||
"customer": "cus_7XTN61mUy646vB",
|
||||
"metadata": {
|
||||
"type": "course",
|
||||
"timestamp": "1449685063457",
|
||||
"timestamp": "1450207546495",
|
||||
"productID": "prepaid course"
|
||||
},
|
||||
"paid": true,
|
||||
|
@ -59,8 +87,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVXKaReE7xLUdFEluXOeu",
|
||||
"customer": "cus_7VCvUi50nXhjWn"
|
||||
"id": "card_17IOQgKaReE7xLUd2XI9u2el",
|
||||
"customer": "cus_7XTN61mUy646vB"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVZKaReE7xLUdc2sd97Kh",
|
||||
"id": "tok_17IOQiKaReE7xLUdJL3Q7JLp",
|
||||
"card": {
|
||||
"id": "card_17GCVZKaReE7xLUdAQ3WCuCA"
|
||||
"id": "card_17IOQiKaReE7xLUd40BrSMNC"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVZKaReE7xLUdLm4xB9Q4",
|
||||
"id": "tok_17IOQjKaReE7xLUdBLKEWC4R",
|
||||
"card": {
|
||||
"id": "card_17GCVZKaReE7xLUdfv42GBHU"
|
||||
"id": "card_17IOQjKaReE7xLUdCbcBVuuk"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVaKaReE7xLUdQP3U2KmC",
|
||||
"id": "tok_17IOQjKaReE7xLUdQx1dIheo",
|
||||
"card": {
|
||||
"id": "card_17GCVaKaReE7xLUdCItK5QND"
|
||||
"id": "card_17IOQjKaReE7xLUdPcrGFELH"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVaKaReE7xLUdfcArqe1K",
|
||||
"id": "tok_17IOQkKaReE7xLUdN8oUK1vt",
|
||||
"card": {
|
||||
"id": "card_17GCVaKaReE7xLUdQXuE34GK"
|
||||
"id": "card_17IOQkKaReE7xLUd89WMMmJy"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVaKaReE7xLUdZqrHnDcB",
|
||||
"id": "tok_17IOQlKaReE7xLUdvcM60UvZ",
|
||||
"card": {
|
||||
"id": "card_17GCVaKaReE7xLUdu0XGOs3Q"
|
||||
"id": "card_17IOQlKaReE7xLUd6KipB1W5"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVbKaReE7xLUdZSSwB8CG",
|
||||
"id": "tok_17IOQmKaReE7xLUdOrulQKjc",
|
||||
"card": {
|
||||
"id": "card_17GCVbKaReE7xLUdsdKXR63y"
|
||||
"id": "card_17IOQmKaReE7xLUd412VlEor"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVbKaReE7xLUdswrosKLO",
|
||||
"id": "tok_17IOQmKaReE7xLUdpGCNDFq8",
|
||||
"card": {
|
||||
"id": "card_17GCVbKaReE7xLUdiINiC8ab"
|
||||
"id": "card_17IOQmKaReE7xLUd0t08mRbC"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVcKaReE7xLUdB5HnT2wI",
|
||||
"id": "tok_17IOQnKaReE7xLUd7vxmypxi",
|
||||
"card": {
|
||||
"id": "card_17GCVcKaReE7xLUd7R94nEhN"
|
||||
"id": "card_17IOQnKaReE7xLUdwvfk7NXJ"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVcKaReE7xLUd7R94nEhN",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQnKaReE7xLUdwvfk7NXJ",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -43,61 +43,78 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVcKaReE7xLUd7R94nEhN",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17IOQnKaReE7xLUdwvfk7NXJ",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVfKaReE7xLUdIvigMi5U",
|
||||
"id": "tok_17IOQqKaReE7xLUdvDFV7zxM",
|
||||
"card": {
|
||||
"id": "card_17GCVfKaReE7xLUdks8zeqw5"
|
||||
"id": "card_17IOQqKaReE7xLUdRqwKR3Vo"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -105,10 +122,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -119,8 +136,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVcKaReE7xLUd7R94nEhN",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQnKaReE7xLUdwvfk7NXJ",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -128,17 +145,17 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -150,10 +167,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -164,8 +181,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVfKaReE7xLUdks8zeqw5",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQnKaReE7xLUdwvfk7NXJ",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -173,17 +190,17 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -195,10 +212,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -209,8 +226,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVfKaReE7xLUdks8zeqw5",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQqKaReE7xLUdRqwKR3Vo",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -218,17 +235,17 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -243,12 +260,12 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVgKaReE7xLUdTqpuyEWR",
|
||||
"amount": 8991,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "ch_17IOQsKaReE7xLUd6vAsPLa6",
|
||||
"amount": 900,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"type": "terminal_subscription",
|
||||
"timestamp": "1449685071367",
|
||||
"timestamp": "1450207556958",
|
||||
"months": "3",
|
||||
"productID": "prepaid terminal_subscription"
|
||||
},
|
||||
|
@ -257,8 +274,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVfKaReE7xLUdks8zeqw5",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQqKaReE7xLUdRqwKR3Vo",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
92
spec/fixtures/db-sub-redeem-test-1.json
vendored
|
@ -2,10 +2,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -16,8 +16,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVfKaReE7xLUdks8zeqw5",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQqKaReE7xLUdRqwKR3Vo",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -25,17 +25,17 @@
|
|||
"subscriptions": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -47,22 +47,22 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM/subscriptions",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -73,22 +73,22 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM/subscriptions",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"data": [
|
||||
{
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -99,20 +99,20 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "DELETE",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM/subscriptions/sub_7VCvEG141oJimL",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t/subscriptions/sub_7XTN0j8yRl2LLW",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "sub_7VCvEG141oJimL",
|
||||
"id": "sub_7XTN0j8yRl2LLW",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363470,
|
||||
"current_period_start": 1449685070,
|
||||
"customer": "cus_7VCvcfu4XzeCbM",
|
||||
"current_period_end": 1452885954,
|
||||
"current_period_start": 1450207554,
|
||||
"customer": "cus_7XTNzqLiTWHO6t",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
@ -120,10 +120,10 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvcfu4XzeCbM",
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -134,8 +134,36 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVfKaReE7xLUdks8zeqw5",
|
||||
"customer": "cus_7VCvcfu4XzeCbM"
|
||||
"id": "card_17IOQqKaReE7xLUdRqwKR3Vo",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7XTNzqLiTWHO6t",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "normal@jo.com",
|
||||
"metadata": {
|
||||
"id": "000000000000000000000088"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17IOQqKaReE7xLUdRqwKR3Vo",
|
||||
"customer": "cus_7XTNzqLiTWHO6t"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -148,7 +176,7 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "GET",
|
||||
"path": "/v1/customers/cus_7VCvcfu4XzeCbM/subscriptions",
|
||||
"path": "/v1/customers/cus_7XTNzqLiTWHO6t/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"has_more": false
|
||||
|
|
50
spec/fixtures/db-sub-redeem-test-2.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVlKaReE7xLUdrgB5G5sg",
|
||||
"id": "tok_17IOQxKaReE7xLUdIT2cvKAt",
|
||||
"card": {
|
||||
"id": "card_17GCVkKaReE7xLUdhnarn1rx"
|
||||
"id": "card_17IOQxKaReE7xLUdls71CTWN"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvhVTldJ0ArC",
|
||||
"id": "cus_7XTN2QmGLf0x5K",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,36 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVkKaReE7xLUdhnarn1rx",
|
||||
"customer": "cus_7VCvhVTldJ0ArC"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
},
|
||||
"subscriptions": {
|
||||
"has_more": false
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvhVTldJ0ArC",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvhVTldJ0ArC",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
"email": "user98@me.com",
|
||||
"metadata": {
|
||||
"id": "00000000000000000000008c"
|
||||
},
|
||||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVkKaReE7xLUdhnarn1rx",
|
||||
"customer": "cus_7VCvhVTldJ0ArC"
|
||||
"id": "card_17IOQxKaReE7xLUdls71CTWN",
|
||||
"customer": "cus_7XTN2QmGLf0x5K"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -74,12 +46,12 @@
|
|||
"path": "/v1/charges",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "ch_17GCVlKaReE7xLUd5D6k1v4E",
|
||||
"amount": 2997,
|
||||
"customer": "cus_7VCvhVTldJ0ArC",
|
||||
"id": "ch_17IOQyKaReE7xLUdftH7lIJF",
|
||||
"amount": 300,
|
||||
"customer": "cus_7XTN2QmGLf0x5K",
|
||||
"metadata": {
|
||||
"type": "terminal_subscription",
|
||||
"timestamp": "1449685077119",
|
||||
"timestamp": "1450207563299",
|
||||
"months": "1",
|
||||
"productID": "prepaid terminal_subscription"
|
||||
},
|
||||
|
@ -88,8 +60,8 @@
|
|||
"has_more": false
|
||||
},
|
||||
"source": {
|
||||
"id": "card_17GCVkKaReE7xLUdhnarn1rx",
|
||||
"customer": "cus_7VCvhVTldJ0ArC"
|
||||
"id": "card_17IOQxKaReE7xLUdls71CTWN",
|
||||
"customer": "cus_7XTN2QmGLf0x5K"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
4
spec/fixtures/db-user-sub-test-1.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVmKaReE7xLUd3TTueitH",
|
||||
"id": "tok_17IOHcKaReE7xLUdfKtGmLgV",
|
||||
"card": {
|
||||
"id": "card_17GCVmKaReE7xLUdErwdQ45K"
|
||||
"id": "card_17IOHcKaReE7xLUdAusILb3u"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
|
22
spec/fixtures/db-user-sub-test-2.json
vendored
|
@ -5,9 +5,9 @@
|
|||
"path": "/v1/tokens",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "tok_17GCVoKaReE7xLUdWKRMzFDb",
|
||||
"id": "tok_17IOHeKaReE7xLUd0xVR8Qcu",
|
||||
"card": {
|
||||
"id": "card_17GCVoKaReE7xLUdpf0crA0p"
|
||||
"id": "card_17IOHeKaReE7xLUdsx1siboK"
|
||||
},
|
||||
"type": "card"
|
||||
}
|
||||
|
@ -18,7 +18,7 @@
|
|||
"path": "/v1/customers",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "cus_7VCvUEDSyqS8aN",
|
||||
"id": "cus_7XTE2tCcVgwJps",
|
||||
"alipay_accounts": {
|
||||
"has_more": false
|
||||
},
|
||||
|
@ -29,8 +29,8 @@
|
|||
"sources": {
|
||||
"data": [
|
||||
{
|
||||
"id": "card_17GCVoKaReE7xLUdpf0crA0p",
|
||||
"customer": "cus_7VCvUEDSyqS8aN"
|
||||
"id": "card_17IOHeKaReE7xLUdsx1siboK",
|
||||
"customer": "cus_7XTE2tCcVgwJps"
|
||||
}
|
||||
],
|
||||
"has_more": false
|
||||
|
@ -43,20 +43,20 @@
|
|||
{
|
||||
"scope": "https://api.stripe.com:443",
|
||||
"method": "POST",
|
||||
"path": "/v1/customers/cus_7VCvUEDSyqS8aN/subscriptions",
|
||||
"path": "/v1/customers/cus_7XTE2tCcVgwJps/subscriptions",
|
||||
"status": 200,
|
||||
"response": {
|
||||
"id": "sub_7VCvXO37PhGOUY",
|
||||
"id": "sub_7XTEeDaljXocIE",
|
||||
"cancel_at_period_end": false,
|
||||
"current_period_end": 1452363481,
|
||||
"current_period_start": 1449685081,
|
||||
"customer": "cus_7VCvUEDSyqS8aN",
|
||||
"current_period_end": 1452885387,
|
||||
"current_period_start": 1450206987,
|
||||
"customer": "cus_7XTE2tCcVgwJps",
|
||||
"metadata": {
|
||||
"id": "0000000000000000000186a1"
|
||||
},
|
||||
"plan": {
|
||||
"id": "basic",
|
||||
"amount": 999
|
||||
"amount": 100
|
||||
},
|
||||
"quantity": 1
|
||||
}
|
||||
|
|