1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-03-21 12:29:03 +01:00

Merge branch 'wallet' into dev

This commit is contained in:
Peng DU 2016-07-21 16:35:43 +02:00
commit 5b3b97fe45
77 changed files with 4648 additions and 217 deletions

View File

@ -1,6 +1,7 @@
# Changelog Fab Manager
## next release
- Add wallet to user, client can pay total/partial reservation or subscription by wallet
- Public calendar for show all trainings/machines/events
- Display 'draft' badge on drafts in project galleries
- Add a 'new project' button in dashboard/my projects

View File

@ -133,6 +133,8 @@ Application.Controllers.controller "InvoicesController", ["$scope", "$state", 'I
sample = sample.replace(/X\[([^\]]+)\]/g, (match, p1, offset, string) ->
p1
)
# information about wallet (W[text]) - does not apply here
sample = sample.replace(/W\[([^\]]+)\]/g, "")
# information about refunds (R[text]) - does not apply here
sample = sample.replace(/R\[([^\]]+)\]/g, "")
sample
@ -494,6 +496,7 @@ Application.Controllers.controller 'AvoirModalController', ["$scope", "$uibModal
{name: _t('by_cash'), value: 'cash'}
{name: _t('by_cheque'), value: 'cheque'}
{name: _t('by_transfer'), value: 'transfer'}
{name: _t('by_wallet'), value: 'wallet'}
]
## If a subscription was took with the current invoice, should it be canceled or not

View File

@ -260,8 +260,8 @@ Application.Controllers.controller "AdminMembersController", ["$scope", 'members
##
# Controller used in the member edition page
##
Application.Controllers.controller "EditMemberController", ["$scope", "$state", "$stateParams", "Member", 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t'
, ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t) ->
Application.Controllers.controller "EditMemberController", ["$scope", "$state", "$stateParams", "Member", 'Training', 'dialogs', 'growl', 'Group', 'Subscription', 'CSRF', 'memberPromise', 'tagsPromise', '$uibModal', 'Plan', '$filter', '_t', 'walletPromise', 'transactionsPromise', 'Wallet'
, ($scope, $state, $stateParams, Member, Training, dialogs, growl, Group, Subscription, CSRF, memberPromise, tagsPromise, $uibModal, Plan, $filter, _t, walletPromise, transactionsPromise, Wallet) ->
@ -300,6 +300,13 @@ Application.Controllers.controller "EditMemberController", ["$scope", "$state",
## Profiles types (student/standard/...)
$scope.groups = []
## the user wallet
$scope.wallet = walletPromise
## user wallet transactions
$scope.transactions = transactionsPromise
$scope.view = 'member_edit'
##
@ -396,6 +403,39 @@ Application.Controllers.controller "EditMemberController", ["$scope", "$state",
$scope.subscription = subscription
$scope.createWalletCreditModal = (user, wallet)->
modalInstance = $uibModal.open
animation: true,
templateUrl: '<%= asset_path "wallet/credit_modal.html" %>'
controller: ['$scope', '$uibModalInstance', 'Wallet', '$locale', ($scope, $uibModalInstance, Wallet, $locale) ->
## currency symbol for the current locale (cf. angular-i18n)
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
##
# Modal dialog validation callback
##
$scope.ok = ->
Wallet.credit { id: wallet.id }, { amount: $scope.amount }, (_wallet)->
growl.success(_t('wallet_credit_successfully'))
$uibModalInstance.close(_wallet)
, (error)->
growl.error(_t('a_problem_occurred_for_wallet_credit'))
##
# Modal dialog cancellation callback
##
$scope.cancel = ->
$uibModalInstance.dismiss('cancel')
]
# once the form was validated succesfully ...
modalInstance.result.then (wallet) ->
$scope.wallet = wallet
Wallet.transactions {id: wallet.id}, (transactions) ->
$scope.transactions = transactions
### PRIVATE SCOPE ###

View File

@ -132,8 +132,8 @@ Application.Controllers.controller "EventsController", ["$scope", "$state", 'Eve
Application.Controllers.controller "ShowEventController", ["$scope", "$state", "$stateParams", "Event", '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'eventPromise', 'reducedAmountAlert', 'growl', '_t'
($scope, $state, $stateParams, Event, $uibModal, Member, Reservation, Price, CustomAsset, eventPromise, reducedAmountAlert, growl, _t) ->
Application.Controllers.controller "ShowEventController", ["$scope", "$state", "$stateParams", "Event", '$uibModal', 'Member', 'Reservation', 'Price', 'CustomAsset', 'eventPromise', 'reducedAmountAlert', 'growl', '_t', 'Wallet', 'helpers',
($scope, $state, $stateParams, Event, $uibModal, Member, Reservation, Price, CustomAsset, eventPromise, reducedAmountAlert, growl, _t, Wallet, helpers) ->
@ -242,11 +242,13 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
if Object.keys($scope.ctrl.member).length > 0
reservation = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event)
if $scope.currentUser.role isnt 'admin' and $scope.reserve.amountTotal > 0
payByStripe(reservation)
else
if $scope.currentUser.role is 'admin' or $scope.reserve.amountTotal is 0
payOnSite(reservation)
Wallet.getWalletByUser {user_id: $scope.ctrl.member.id}, (wallet) ->
amountToPay = helpers.getAmountToPay($scope.reserve.amountTotal, wallet.amount)
if $scope.currentUser.role isnt 'admin' and amountToPay > 0
payByStripe(reservation)
else
if $scope.currentUser.role is 'admin' or amountToPay is 0
payOnSite(reservation)
else
# otherwise we alert, this error musn't occur when the current user is not admin
growl.error(_t('please_select_a_member_first'))
@ -461,15 +463,20 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
reservation
price: ->
Price.compute({reservation: reservation}).$promise
wallet: ->
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
cgv: ->
CustomAsset.get({name: 'cgv-file'}).$promise
objectToPay: ->
eventToReserve: $scope.event
reserve: $scope.reserve
member: $scope.ctrl.member
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'growl', ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, growl) ->
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'growl', 'wallet', 'helpers', '$locale', '$filter', ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, growl, wallet, helpers, $locale, $filter) ->
# user wallet amount
$scope.walletAmount = wallet.amount
# Price
$scope.amount = price.price
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount)
# CGV
$scope.cgv = cgv.custom_asset
@ -477,6 +484,10 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
# Reservation
$scope.reservation = reservation
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
# Callback for the stripe payment authorization
$scope.payment = (status, response) ->
if response.error
@ -511,18 +522,34 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
reservation
price: ->
Price.compute({reservation: reservation}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation) ->
wallet: ->
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', '$locale', 'helpers', '$filter', ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, $locale, helpers, $filter) ->
# user wallet amount
$scope.walletAmount = wallet.amount
# Price
$scope.amount = price.price
$scope.price = price.price
# price to pay
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount)
# Reservation
$scope.reservation = reservation
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
# Button label
confirmPaymentText = if $scope.currentUser.role == 'admin' then _t('confirm_client_payment_of_') else _t('confirm_my_payment_of_')
if $scope.amount > 0
$scope.validButtonName = _t('confirm_(payment_on_site)')
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')($scope.amount)}"
else
$scope.validButtonName = _t('confirm')
if price.price > 0 and $scope.walletAmount == 0
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')(price.price)}"
else
$scope.validButtonName = _t('confirm')
# Callback to validate the payment
$scope.ok = ->

View File

@ -268,8 +268,8 @@ Application.Controllers.controller "ShowMachineController", ['$scope', '$state',
# This controller workflow is pretty similar to the trainings reservation controller.
##
Application.Controllers.controller "ReserveMachineController", ["$scope", "$state", '$stateParams', "$uibModal", '_t', "moment", 'Machine', 'Auth', 'dialogs', '$timeout', 'Price', 'Member', 'Availability', 'Slot', 'Setting', 'CustomAsset', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'uiCalendarConfig', 'CalendarConfig'
($scope, $state, $stateParams, $uibModal, _t, moment, Machine, Auth, dialogs, $timeout, Price, Member, Availability, Slot, Setting, CustomAsset, plansPromise, groupsPromise, growl, settingsPromise, uiCalendarConfig, CalendarConfig) ->
Application.Controllers.controller "ReserveMachineController", ["$scope", "$state", '$stateParams', "$uibModal", '_t', "moment", 'Machine', 'Auth', 'dialogs', '$timeout', 'Price', 'Member', 'Availability', 'Slot', 'Setting', 'CustomAsset', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'Wallet', 'helpers', 'uiCalendarConfig', 'CalendarConfig',
($scope, $state, $stateParams, $uibModal, _t, moment, Machine, Auth, dialogs, $timeout, Price, Member, Availability, Slot, Setting, CustomAsset, plansPromise, groupsPromise, growl, settingsPromise, Wallet, helpers, uiCalendarConfig, CalendarConfig) ->
@ -529,11 +529,13 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
if Object.keys($scope.ctrl.member).length > 0
reservation = mkReservation($scope.ctrl.member, $scope.eventsReserved, $scope.selectedPlan)
if $scope.currentUser.role isnt 'admin' and $scope.amountTotal > 0
payByStripe(reservation)
else
if $scope.currentUser.role is 'admin' or $scope.amountTotal is 0
payOnSite(reservation)
Wallet.getWalletByUser {user_id: $scope.ctrl.member.id}, (wallet) ->
amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount)
if $scope.currentUser.role isnt 'admin' and amountToPay > 0
payByStripe(reservation)
else
if $scope.currentUser.role is 'admin' or amountToPay is 0
payOnSite(reservation)
else
# otherwise we alert, this error musn't occur when the current user is not admin
growl.error(_t('please_select_a_member_first'))
@ -752,11 +754,16 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
reservation
price: ->
Price.compute({reservation: reservation}).$promise
wallet: ->
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
cgv: ->
CustomAsset.get({name: 'cgv-file'}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation) ->
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'wallet', 'helpers', '$locale', '$filter', ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, wallet, helpers, $locale, $filter) ->
# user wallet amount
$scope.walletAmount = wallet.amount
# Price
$scope.amount = price.price
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount)
# CGV
$scope.cgv = cgv.custom_asset
@ -764,6 +771,10 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
# Reservation
$scope.reservation = reservation
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
##
# Callback to process the payment with Stripe, triggered on button click
##
@ -800,19 +811,34 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
reservation
price: ->
Price.compute({reservation: reservation}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation) ->
wallet: ->
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', '$locale', ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, helpers, $filter, $locale) ->
# user wallet amount
$scope.walletAmount = wallet.amount
# Price
$scope.amount = price.price
$scope.price = price.price
# price to pay
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount)
# Reservation
$scope.reservation = reservation
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
# Button label
confirmPaymentText = if $scope.currentUser.role == 'admin' then _t('confirm_client_payment_of_') else _t('confirm_my_payment_of_')
if $scope.amount > 0
$scope.validButtonName = _t('confirm_(payment_on_site)')
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')($scope.amount)}"
else
$scope.validButtonName = _t('confirm')
if price.price > 0 and $scope.walletAmount == 0
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')(price.price)}"
else
$scope.validButtonName = _t('confirm')
##
# Callback to process the local payment, triggered on button click

View File

@ -1,7 +1,7 @@
'use strict'
Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScope", "$state", '$uibModal', 'Auth', 'dialogs', 'growl', 'plansPromise', 'groupsPromise', 'Subscription', 'Member', 'subscriptionExplicationsPromise', '_t'
, ($scope, $rootScope, $state, $uibModal, Auth, dialogs, growl, plansPromise, groupsPromise, Subscription, Member, subscriptionExplicationsPromise, _t) ->
Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScope", "$state", '$uibModal', 'Auth', 'dialogs', 'growl', 'plansPromise', 'groupsPromise', 'Subscription', 'Member', 'subscriptionExplicationsPromise', '_t', 'Wallet', 'helpers'
, ($scope, $rootScope, $state, $uibModal, Auth, dialogs, growl, plansPromise, groupsPromise, Subscription, Member, subscriptionExplicationsPromise, _t, Wallet, helpers) ->
@ -72,10 +72,13 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
# Callback to trigger the payment process of the subscription
##
$scope.openSubscribePlanModal = ->
if $scope.currentUser.role isnt 'admin'
payByStripe()
else
payOnSite()
Wallet.getWalletByUser {user_id: $scope.ctrl.member.id}, (wallet) ->
amountToPay = helpers.getAmountToPay($scope.selectedPlan.amount, wallet.amount)
if $scope.currentUser.role isnt 'admin' and amountToPay > 0
payByStripe()
else
if $scope.currentUser.role is 'admin' or amountToPay is 0
payOnSite()
@ -162,9 +165,20 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
resolve:
selectedPlan: -> $scope.selectedPlan
member: -> $scope.ctrl.member
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'Subscription', 'CustomAsset', ($scope, $uibModalInstance, $state, selectedPlan, member, Subscription, CustomAsset) ->
$scope.amount = selectedPlan.amount
wallet: ->
Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'Subscription', 'CustomAsset', 'wallet', 'helpers', '$locale', '$filter', ($scope, $uibModalInstance, $state, selectedPlan, member, Subscription, CustomAsset, wallet, helpers, $locale, $filter) ->
# user wallet amount
$scope.walletAmount = wallet.amount
$scope.amount = helpers.getAmountToPay(selectedPlan.amount, wallet.amount)
$scope.selectedPlan = selectedPlan
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
# retrieve the CGV
CustomAsset.get {name: 'cgv-file'}, (cgv) ->
$scope.cgv = cgv.custom_asset
@ -203,9 +217,34 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
resolve:
selectedPlan: -> $scope.selectedPlan
member: -> $scope.ctrl.member
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'Subscription', ($scope, $uibModalInstance, $state, selectedPlan, member, Subscription) ->
wallet: ->
Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'Subscription', 'wallet', 'helpers', '$locale', '$filter', ($scope, $uibModalInstance, $state, selectedPlan, member, Subscription, wallet, helpers, $locale, $filter) ->
# user wallet amount
$scope.walletAmount = wallet.amount
$scope.price = selectedPlan.amount
# price to pay
$scope.amount = helpers.getAmountToPay($scope.price, wallet.amount)
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
$scope.plan = selectedPlan
$scope.member = member
# Button label
confirmPaymentText = if $scope.currentUser.role == 'admin' then _t('confirm_client_payment_of_') else _t('confirm_my_payment_of_')
if $scope.amount > 0
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')($scope.amount)}"
else
if price.price > 0 and $scope.walletAmount == 0
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')(price.price)}"
else
$scope.validButtonName = _t('confirm')
$scope.ok = ->
$scope.attempting = true
Subscription.save

View File

@ -51,8 +51,8 @@ Application.Controllers.controller "ShowTrainingController", ['$scope', '$state'
# training can be reserved during the reservation process (the shopping cart may contains only one training and a subscription).
##
Application.Controllers.controller "ReserveTrainingController", ["$scope", "$state", '$stateParams', '$filter', '$compile', "$uibModal", 'Auth', 'dialogs', '$timeout', 'Price', 'Availability', 'Slot', 'Member', 'Setting', 'CustomAsset', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'trainingPromise', '_t', 'uiCalendarConfig', 'CalendarConfig'
($scope, $state, $stateParams, $filter, $compile, $uibModal, Auth, dialogs, $timeout, Price, Availability, Slot, Member, Setting, CustomAsset, availabilityTrainingsPromise, plansPromise, groupsPromise, growl, settingsPromise, trainingPromise, _t, uiCalendarConfig, CalendarConfig) ->
Application.Controllers.controller "ReserveTrainingController", ["$scope", "$state", '$stateParams', '$filter', '$compile', "$uibModal", 'Auth', 'dialogs', '$timeout', 'Price', 'Availability', 'Slot', 'Member', 'Setting', 'CustomAsset', 'availabilityTrainingsPromise', 'plansPromise', 'groupsPromise', 'growl', 'settingsPromise', 'trainingPromise', '_t', 'Wallet', 'helpers', 'uiCalendarConfig', 'CalendarConfig'
($scope, $state, $stateParams, $filter, $compile, $uibModal, Auth, dialogs, $timeout, Price, Availability, Slot, Member, Setting, CustomAsset, availabilityTrainingsPromise, plansPromise, groupsPromise, growl, settingsPromise, trainingPromise, _t, Wallet, helpers, uiCalendarConfig, CalendarConfig) ->
@ -188,11 +188,13 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
if Object.keys($scope.ctrl.member).length > 0
reservation = mkReservation($scope.ctrl.member, $scope.selectedTraining, $scope.selectedPlan)
if $scope.currentUser.role isnt 'admin' and $scope.amountTotal > 0
payByStripe(reservation)
else
if $scope.currentUser.role is 'admin' or $scope.amountTotal is 0
payOnSite(reservation)
Wallet.getWalletByUser {user_id: $scope.ctrl.member.id}, (wallet) ->
amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount)
if $scope.currentUser.role isnt 'admin' and amountToPay > 0
payByStripe(reservation)
else
if $scope.currentUser.role is 'admin' or amountToPay is 0
payOnSite(reservation)
else
# otherwise we alert, this error musn't occur when the current user is not admin
growl.error(_t('please_select_a_member_first'))
@ -474,11 +476,16 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
reservation
price: ->
Price.compute({reservation: reservation}).$promise
wallet: ->
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
cgv: ->
CustomAsset.get({name: 'cgv-file'}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', ($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation) ->
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'wallet', 'cgv', 'Auth', 'Reservation', '$locale', 'helpers', '$filter', ($scope, $uibModalInstance, $state, reservation, price, wallet, cgv, Auth, Reservation, $locale, helpers, $filter) ->
# user wallet amount
$scope.walletAmount = wallet.amount
# Price
$scope.amount = price.price
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount)
# CGV
$scope.cgv = cgv.custom_asset
@ -486,6 +493,10 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
# Reservation
$scope.reservation = reservation
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
##
# Callback to process the payment with Stripe, triggered on button click
##
@ -525,18 +536,34 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
reservation
price: ->
Price.compute({reservation: reservation}).$promise
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', ($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation) ->
wallet: ->
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
controller: ['$scope', '$uibModalInstance', '$state', '$filter', 'reservation', 'price', 'wallet', 'Auth', 'Reservation', '$locale', 'helpers', ($scope, $uibModalInstance, $state, $filter, reservation, price, wallet, Auth, Reservation, $locale, helpers) ->
# user wallet amount
$scope.walletAmount = wallet.amount
# Price
$scope.amount = price.price
$scope.price = price.price
# price to pay
$scope.amount = helpers.getAmountToPay(price.price, wallet.amount)
# Reservation
$scope.reservation = reservation
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
$scope.numberFilter = $filter('number')
# Button label
confirmPaymentText = if $scope.currentUser.role == 'admin' then _t('confirm_client_payment_of_') else _t('confirm_my_payment_of_')
if $scope.amount > 0
$scope.validButtonName = _t('confirm_(payment_on_site)')
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')($scope.amount)}"
else
$scope.validButtonName = _t('confirm')
if price.price > 0 and $scope.walletAmount == 0
$scope.validButtonName = "#{confirmPaymentText} #{$filter('currency')(price.price)}"
else
$scope.validButtonName = _t('confirm')
##
# Callback to process the local payment, triggered on button click

View File

@ -0,0 +1,12 @@
'use strict'
Application.Controllers.controller "WalletController", ['$scope', 'walletPromise', 'transactionsPromise', ($scope, walletPromise, transactionsPromise)->
### PUBLIC SCOPE ###
## current user wallet
$scope.wallet = walletPromise
## current wallet transactions
$scope.transactions = transactionsPromise
]

View File

@ -197,6 +197,22 @@ angular.module('application.router', ['ui.router']).
translations: [ 'Translations', (Translations) ->
Translations.query('app.logged.dashboard.invoices').$promise
]
.state 'app.logged.dashboard.wallet',
url: '/wallet'
views:
'main@':
templateUrl: '<%= asset_path "dashboard/wallet.html" %>'
controller: 'WalletController'
resolve:
walletPromise: ['Wallet', 'currentUser', (Wallet, currentUser)->
Wallet.getWalletByUser(user_id: currentUser.id).$promise
]
transactionsPromise: ['Wallet', 'walletPromise', (Wallet, walletPromise)->
Wallet.transactions(id: walletPromise.id).$promise
]
translations: [ 'Translations', (Translations) ->
Translations.query(['app.shared.wallet']).$promise
]
# members
@ -347,7 +363,7 @@ angular.module('application.router', ['ui.router']).
]
translations: [ 'Translations', (Translations) ->
Translations.query(['app.logged.machines_reserve', 'app.shared.plan_subscribe', 'app.shared.member_select',
'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal']).$promise
'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal', 'app.shared.wallet']).$promise
]
.state 'app.admin.machines_edit',
url: '/machines/:id/edit'
@ -424,7 +440,7 @@ angular.module('application.router', ['ui.router']).
]
translations: [ 'Translations', (Translations) ->
Translations.query(['app.logged.trainings_reserve', 'app.shared.plan_subscribe', 'app.shared.member_select',
'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal']).$promise
'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.confirm_modify_slot_modal', 'app.shared.wallet']).$promise
]
# notifications
.state 'app.logged.notifications',
@ -457,7 +473,7 @@ angular.module('application.router', ['ui.router']).
Group.query().$promise
]
translations: [ 'Translations', (Translations) ->
Translations.query(['app.public.plans', 'app.shared.member_select', 'app.shared.stripe']).$promise
Translations.query(['app.public.plans', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.wallet']).$promise
]
# events
@ -494,7 +510,7 @@ angular.module('application.router', ['ui.router']).
Setting.get(name: 'event_reduced_amount_alert').$promise
]
translations: [ 'Translations', (Translations) ->
Translations.query(['app.public.events_show', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.valid_reservation_modal']).$promise
Translations.query(['app.public.events_show', 'app.shared.member_select', 'app.shared.stripe', 'app.shared.valid_reservation_modal', 'app.shared.wallet']).$promise
]
# calendar global (trainings, machines and events)
@ -859,11 +875,17 @@ angular.module('application.router', ['ui.router']).
memberPromise: ['Member', '$stateParams', (Member, $stateParams)->
Member.get(id: $stateParams.id).$promise
]
walletPromise: ['Wallet', '$stateParams', (Wallet, $stateParams)->
Wallet.getWalletByUser(user_id: $stateParams.id).$promise
]
transactionsPromise: ['Wallet', 'walletPromise', (Wallet, walletPromise)->
Wallet.transactions(id: walletPromise.id).$promise
]
tagsPromise: ['Tag', (Tag)->
Tag.query().$promise
]
translations: [ 'Translations', (Translations) ->
Translations.query(['app.admin.members_edit', 'app.shared.user', 'app.shared.user_admin']).$promise
Translations.query(['app.admin.members_edit', 'app.shared.user', 'app.shared.user_admin', 'app.shared.wallet']).$promise
]
.state 'app.admin.admins_new',
url: '/admin/admins/new'

View File

@ -0,0 +1,6 @@
'use strict'
Application.Services.factory 'helpers', [()->
getAmountToPay: (price, walletAmount)->
if walletAmount > price then 0 else price - walletAmount
]

View File

@ -0,0 +1,18 @@
'use strict'
Application.Services.factory 'Wallet', ["$resource", ($resource)->
$resource "/api/wallet",
{},
getWalletByUser:
method: 'GET'
url: '/api/wallet/by_user/:user_id'
isArray: false
transactions:
method: 'GET'
url: '/api/wallet/:id/transactions'
isArray: true
credit:
method: 'PUT'
url: '/api/wallet/:id/credit'
isArray: false
]

View File

@ -39,3 +39,4 @@
.text-purple { color: $violet !important; }
.text-japonica { color: $japonica !important; }
.text-beige { color: $beige !important; }
.text-green, .green { color: #79C84A !important; }

View File

@ -514,3 +514,48 @@ padding: 10px;
border-radius: 3px;
}
}
.wallet-amount-container {
padding: 20px 0;
border-top: 2px dotted $border-color;
border-bottom: 2px dotted $border-color;
margin-bottom: 20px;
text-align: center;
.wallet-amount {
font-size: rem-calc(40);
font-weight: 700;
font-style: italic;
color: #616161;
span {
font-weight: 500;
font-size: .7em;
}
&.cr-green {
color: $green;
}
}
}
.amountGroup {
input {
display: inline-block;
width: 100px;
margin-left: 5px;
padding-right: 6px;
font-weight: bold;
color: $green;
font-size: 1.2em;
line-height: 0;
}
.afterAmount {
margin-left: -35px;
font-weight: bold;
color: $green;
font-size: 1.2em;
line-height: 0;
}
}

View File

@ -210,6 +210,7 @@
<li ng-click="invoice.reference.help = 'addDay.html'">{{ 'day' | translate }}</li>
<li ng-click="invoice.reference.help = 'addInvoiceNumber.html'">{{ '#_of_invoice' | translate }}</li>
<li ng-click="invoice.reference.help = 'addOnlineInfo.html'">{{ 'online_sales' | translate }}</li>
<li ng-click="invoice.reference.help = 'addWalletInfo.html'">{{ 'wallet' | translate }}</li>
<li ng-click="invoice.reference.help = 'addRefundInfo.html'">{{ 'refund' | translate }}</li>
</ul>
</div>
@ -279,6 +280,12 @@
</table>
</script>
<script type="text/ng-template" id="addWalletInfo.html">
<table class="invoice-element-legend">
<tr><td><strong>W[texte]</strong></td><td>{{ 'add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned' | translate }} <mark translate>{{ 'this_will_never_be_added_when_a_refund_notice_is_present' }}</mark> {{ '(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet)' | translate }}</td></tr>
</table>
</script>
<script type="text/ng-template" id="addRefundInfo.html">
<table class="invoice-element-legend">
<tr><td><strong>R[texte]</strong></td><td>{{ 'add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned' | translate }}<mark translate>{{ 'this_will_never_be_added_when_an_online_sales_notice_is_present' }}</mark> {{ '(eg_R[/A]_will_add_/A_to_the_refund_invoices)' | translate }}</td></tr>
@ -383,4 +390,4 @@
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
</div>
</div>
</script>
</script>

View File

@ -215,6 +215,22 @@
</div>
</uib-tab>
<uib-tab heading="{{ 'wallet' | translate }}">
<div class="col-md-12 m m-t-lg">
<ng-include src="'<%= asset_path 'wallet/show.html' %>'"></ng-include>
<div class="clearfix"></div>
<div class="col-sm-4 text-center">
<button type="button" class="btn btn-warning m-t m-b" ng-click="createWalletCreditModal(user, wallet)" translate>{{ 'to_credit' }}</button>
</div>
</div>
<div class="col-md-12 m m-t-lg">
<ng-include src="'<%= asset_path 'wallet/transactions.html' %>'"></ng-include>
</div>
</uib-tab>
</uib-tabset>
</div>

View File

@ -8,15 +8,16 @@
</div>
<div class="col-xs-10 col-sm-10 col-md-10 b-l">
<section class="heading-title m-l">
<h4 class="m-l text-sm" translate>{{ 'dashboard' }}</h4>
<ul class="nav-page nav nav-pills text-u-c text-sm">
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.profile" translate>{{ 'my_profile' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.settings" translate>{{ 'my_settings' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.projects" translate>{{ 'my_projects' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.trainings" translate>{{ 'my_trainings' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.events" translate>{{ 'my_events' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.invoices" translate>{{ 'my_invoices' }}</a></li>
</ul>
<h4 class="m-l text-sm" translate>{{ 'dashboard' }}</h4>
<ul class="nav-page nav nav-pills text-u-c text-sm">
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.profile" translate>{{ 'my_profile' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.settings" translate>{{ 'my_settings' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.projects" translate>{{ 'my_projects' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.trainings" translate>{{ 'my_trainings' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.events" translate>{{ 'my_events' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.invoices" translate>{{ 'my_invoices' }}</a></li>
<li ui-sref-active="active"><a class="text-black" href="#" ui-sref="app.logged.dashboard.wallet" translate>{{ 'my_wallet' }}</a></li>
</ul>
</section>
</div>
</div>

View File

@ -0,0 +1,21 @@
<div>
<section class="heading">
<div class="row no-gutter">
<ng-include src="'<%= asset_path 'dashboard/nav.html' %>'"></ng-include>
</div>
</section>
<div class="row no-gutter">
<div class="col-md-12 m m-t-lg">
<ng-include src="'<%= asset_path 'wallet/show.html' %>'"></ng-include>
</div>
<div class="col-md-12 m m-t-lg">
<ng-include src="'<%= asset_path 'wallet/transactions.html' %>'"></ng-include>
</div>
</div>
</div>
</div>

View File

@ -3,10 +3,12 @@
<h1 translate>{{ 'subscription_confirmation' }}</h1>
</div>
<div class="modal-body">
<ng-include src="'<%= asset_path 'shared/_wallet_amount_info.html' %>'"></ng-include>
<p>{{ 'here_is_the_NAME_subscription_summary' | translate:{NAME:member.name} }}</p>
<p>{{ plan | humanReadablePlanName }}</p>
</div>
<div class="modal-footer">
<button class="btn btn-info" ng-click="ok()" ng-disabled="attempting" translate>{{ 'confirm_(payment_on_site)' }}</button>
<button class="btn btn-info" ng-click="ok()" ng-disabled="attempting">{{validButtonName}}</button>
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
</div>

View File

@ -0,0 +1,10 @@
<div ng-if="currentUser.role != 'admin'">
<h3 class="m-t-xs" ng-if="walletAmount > 0 && price > 0">{{ 'you_have_amount_in_wallet' | translate:{ amount: numberFilter(walletAmount, 2), currency: currencySymbol } }}</h3>
<p ng-if="walletAmount > 0 && price > 0 && amount === 0" class="text-italic">{{'wallet_pay_reservation' | translate}}</p>
<p ng-if="walletAmount > 0 && amount !== 0" class="text-italic">{{'credit_amount_for_pay_reservation' | translate:{ amount: numberFilter(amount, 2), currency: currencySymbol } }}</p>
</div>
<div ng-if="currentUser.role == 'admin'">
<h3 class="m-t-xs" ng-if="walletAmount > 0 && price > 0">{{ 'client_have_amount_in_wallet' | translate:{ amount: numberFilter(walletAmount, 2), currency: currencySymbol } }}</h3>
<p ng-if="walletAmount > 0 && price > 0 && amount === 0" class="text-italic">{{'client_wallet_pay_reservation' | translate}}</p>
<p ng-if="walletAmount > 0 && amount !== 0" class="text-italic">{{'client_credit_amount_for_pay_reservation' | translate:{ amount: numberFilter(amount, 2), currency: currencySymbol } }}</p>
</div>

View File

@ -40,6 +40,7 @@
<li><a href="#" ui-sref="app.logged.dashboard.trainings" translate>{{ 'my_trainings' }}</a></li>
<li><a href="#" ui-sref="app.logged.dashboard.events" translate>{{ 'my_events' }}</a></li>
<li><a href="#" ui-sref="app.logged.dashboard.invoices" translate>{{ 'my_invoices' }}</a></li>
<li><a href="#" ui-sref="app.logged.dashboard.wallet" translate>{{ 'my_wallet' }}</a></li>
<li class="divider"></li>
<li><a href="#" class="text-black" ng-click="logout($event)"><i class="fa fa-power-off"></i> {{ 'sign_out' | translate }}</a></li>

View File

@ -3,6 +3,8 @@
<h1 translate>{{ 'booking_confirmation' }}</h1>
</div>
<div class="modal-body">
<ng-include src="'<%= asset_path 'shared/_wallet_amount_info.html' %>'"></ng-include>
<p translate>{{ 'here_is_the_summary_of_the_slots_to_book_for_the_current_user' }}</p>
<ul ng-repeat="slot in reservation.slots_attributes">
<li><strong>{{slot.start_at | amDateFormat: 'LL'}} : {{slot.start_at | amDateFormat:'LT'}} - {{slot.end_at | amDateFormat:'LT'}}</strong></li>

View File

@ -10,14 +10,8 @@
<form name="stripeForm" stripe:form="payment" class="form-horizontal">
<div class="panel-body">
<div class="form-group" ng-class="{'has-error': stripeForm.acceptCondition.$dirty && stripeForm.acceptCondition.$invalid}" ng-show="cgv">
<div class="col-sm-12 text-sm">
<input type="checkbox" name="acceptCondition" ng-model="acceptCondition" value="true" ng-required="cgv != null"/> {{ 'i_have_read_and_accept_' | translate }} <a href="{{cgv.custom_asset_file_attributes.attachment_url}}" target="_blank" translate>{{ '_the_general_terms_and_conditions' }}</a>
</div>
<div ng-if="!cgv">
<input type="hidden" name="acceptCondition" ng-model="acceptCondition" value="true">
</div>
</div>
<h3 class="m-t-xs" ng-if="walletAmount">{{ 'you_have_amount_in_wallet' | translate:{ amount: numberFilter(walletAmount, 2), currency: currencySymbol } }}</h3>
<p ng-if="walletAmount > 0 && amount !== 0" class="text-italic">{{'credit_amount_for_pay_reservation' | translate:{ amount: numberFilter(amount, 2), currency: currencySymbol } }}</p>
<div class="form-group" ng-class="{'has-error': stripeForm.number.$dirty && stripeForm.number.$invalid}">
<div class="col-sm-12">
@ -37,6 +31,15 @@
</div>
</div>
<div class="form-group" ng-class="{'has-error': stripeForm.acceptCondition.$dirty && stripeForm.acceptCondition.$invalid}" ng-show="cgv">
<div class="col-sm-12 text-sm">
<input type="checkbox" name="acceptCondition" ng-model="acceptCondition" value="true" ng-required="cgv != null"/> {{ 'i_have_read_and_accept_' | translate }} <a href="{{cgv.custom_asset_file_attributes.attachment_url}}" target="_blank" translate>{{ '_the_general_terms_and_conditions' }}</a>
</div>
<div ng-if="!cgv">
<input type="hidden" name="acceptCondition" ng-model="acceptCondition" value="true">
</div>
</div>
</div>
<div class="panel-footer no-padder">
<button type="submit" class="btn btn-valid btn-info btn-block p-l btn-lg text-u-c r-b text-base" ng-disabled="stripeForm.$invalid || attempting">{{ 'confirm_my_payment_of_' | translate }} {{ amount | currency }}</button>

View File

@ -0,0 +1,20 @@
<div class="modal-header">
<img ng-src="{{logoBlack.custom_asset_file_attributes.attachment_url}}" alt="{{logo.custom_asset_file_attributes.attachment}}" class="modal-logo"/>
<h1 translate>{{ 'credit_title' }}</h1>
</div>
<div class="modal-body">
<form name="walletForm" ng-class="{'has-error': walletForm.amount.$dirty && walletForm.amount.$invalid}">
<div class="text-center amountGroup">
<span class="beforeAmount" translate>{{ 'credit_label' }}</span>
<input class="form-control" type="number" name="amount" ng-model="amount" required min="1" step="any">
<span class="afterAmount">{{currencySymbol}}</span>
<span class="help-block" ng-show="walletForm.amount.$dirty && walletForm.amount.$error.required" translate>{{'amount_is_required'}}</span>
<span class="help-block" ng-show="walletForm.amount.$dirty && walletForm.amount.$error.min">{{ 'amount_minimum_1' | translate }}{{currencySymbol}}</span>
</div>
</form>
</div>
<div class="modal-footer">
<button class="btn btn-info" ng-click="ok()" ng-disabled="walletForm.$invalid || attempting" translate>{{ 'confirm' }}</button>
<button class="btn btn-default" ng-click="cancel()" translate>{{ 'cancel' }}</button>
</div>

View File

@ -0,0 +1,7 @@
<div class="col-sm-4 text-center">
<h4 translate ng-if="view !== 'member_edit'">{{'your_wallet_amount'}}</h4>
<h4 translate ng-if="view === 'member_edit'">{{'wallet_amount'}}</h4>
<div class="wallet-amount-container">
<div class="wallet-amount">{{wallet.amount | currency}}</div>
</div>
</div>

View File

@ -0,0 +1,31 @@
<div>
<table class="table" ng-if="transactions.length > 0">
<thead>
<tr>
<th style="width:25%" translate>{{ 'date' }}</th>
<th style="width:25%" translate>{{ 'operation' }}</th>
<th style="width:25%" translate>{{ 'operator' }}</th>
<th style="width:25%" translate>{{ 'amount' }}</th>
</tr>
</thead>
<tbody>
<tr ng-repeat="t in transactions">
<td>{{ ::t.created_at | amDateFormat:'L' }}</td>
<td>
<span ng-if="t.transaction_type == 'credit'" translate>{{ 'credit' }}</span>
<span ng-if="t.transaction_type == 'debit'" translate>{{ 'debit' }}</span>
<a ng-href="api/invoices/{{t.invoice.id}}/download" target="_blank" ng-if="t.invoice.id">
{{::t.invoice.reference}}
</a>
</td>
<td>{{ ::t.user.full_name }}</td>
<td ng-class="{'green':t.transaction_type == 'credit', 'red':t.transaction_type == 'debit'}">
<span ng-if="t.transaction_type == 'credit'">+</span>
<span ng-if="t.transaction_type == 'debit'">-</span>
<strong>{{ ::t.amount | currency }}</strong>
</td>
</tr>
</tbody>
</table>
<p ng-if="transactions.length == 0" translate>{{ 'no_transactions_for_now' }}</p>
</div>

View File

@ -18,8 +18,10 @@ class API::SubscriptionsController < API::ApiController
@subscription.attributes = subscription_params
is_subscribe = @subscription.save_with_local_payment(!User.find(subscription_params[:user_id]).invoicing_disabled?)
else
member = User.find(subscription_params[:user_id])
plan = Plan.find(subscription_params[:plan_id])
@subscription = Subscription.find_or_initialize_by(user_id: current_user.id)
if valid_card_token?(subscription_params[:card_token])
if valid_card_token?(subscription_params[:card_token]) or (member.wallet.amount >= plan.amount / 100.0)
@subscription.update_column(:expired_at, nil) unless @subscription.new_record? # very important
@subscription.attributes = subscription_params.merge(user_id: current_user.id)
is_subscribe = @subscription.save_with_payment

View File

@ -0,0 +1,26 @@
class API::WalletController < API::ApiController
before_action :authenticate_user!
def by_user
@wallet = Wallet.find_by(user_id: params[:user_id])
authorize @wallet
render :show
end
def transactions
@wallet = Wallet.find(params[:id])
authorize @wallet
@wallet_transactions = @wallet.wallet_transactions.includes(:invoice, user: [:profile]).order(created_at: :desc)
end
def credit
@wallet = Wallet.find(params[:id])
authorize @wallet
service = WalletService.new(user: current_user, wallet: @wallet)
if service.credit(params[:amount].to_f)
render :show
else
head 422
end
end
end

View File

@ -52,6 +52,10 @@ module ApplicationHelper
if (bool) then return :true else return :false end
end
def amount_to_f(amount)
amount / 100.00
end
private
## inspired by gems/actionview-4.2.5/lib/action_view/helpers/translation_helper.rb

View File

@ -2,7 +2,7 @@ class Avoir < Invoice
belongs_to :invoice
after_create :expire_subscription, if: :subscription_to_expire
validates :avoir_mode, :inclusion => {:in => %w(stripe cheque transfer none cash)}
validates :avoir_mode, :inclusion => {:in => %w(stripe cheque transfer none cash wallet)}
attr_accessor :invoice_items_ids

View File

@ -0,0 +1,23 @@
module AmountConcern
extend ActiveSupport::Concern
included do
validates_numericality_of :amount, greater_than_or_equal_to: 0
def amount=(amount)
if amount.nil?
write_attribute(:amount, amount)
else
write_attribute(:amount, (amount * 100).to_i)
end
end
def amount
if read_attribute(:amount).blank?
read_attribute(:amount)
else
read_attribute(:amount) / 100.0
end
end
end
end

View File

@ -7,6 +7,7 @@ class Invoice < ActiveRecord::Base
has_many :invoice_items, dependent: :destroy
accepts_nested_attributes_for :invoice_items
belongs_to :user
belongs_to :wallet_transaction
has_one :avoir, class_name: 'Invoice', foreign_key: :invoice_id, dependent: :destroy
@ -66,6 +67,9 @@ class Invoice < ActiveRecord::Base
reference.gsub!(/X\[([^\]]+)\]/, ''.to_s)
end
# information about wallet (W[text])
reference.gsub!(/W\[([^\]]+)\]/, ''.to_s)
# remove information about refunds (R[text])
reference.gsub!(/R\[([^\]]+)\]/, ''.to_s)

View File

@ -37,5 +37,7 @@ class NotificationType
notify_admin_profile_complete
notify_admin_abuse_reported
notify_admin_invoicing_changed
notify_user_wallet_is_credited
notify_admin_user_wallet_is_credited
)
end

View File

@ -17,6 +17,7 @@ class Reservation < ActiveRecord::Base
after_commit :notify_member_create_reservation, on: :create
after_commit :notify_admin_member_create_reservation, on: :create
after_save :update_event_nb_free_places, if: Proc.new { |reservation| reservation.reservable_type == 'Event' }
after_create :debit_user_wallet
#
# Generate an array of {Stripe::InvoiceItem} with the elements in the current reservation, price included.
@ -124,6 +125,16 @@ class Reservation < ActiveRecord::Base
end
@wallet_amount_debit = get_wallet_amount_debit
if @wallet_amount_debit != 0 and !on_site
invoice_items << Stripe::InvoiceItem.create(
customer: user.stp_customer_id,
amount: -@wallet_amount_debit,
currency: Rails.application.secrets.stripe_currency,
description: "wallet -#{@wallet_amount_debit / 100.0}"
)
end
# let's return the resulting array of items
invoice_items
end
@ -170,49 +181,49 @@ class Reservation < ActiveRecord::Base
#
# IMPORTANT NOTE: here, we have to create an invoice manually and pay it to pay all waiting stripe invoice items
#
invoice = Stripe::Invoice.create(
stp_invoice = Stripe::Invoice.create(
customer: user.stp_customer_id,
)
invoice.pay
stp_invoice.pay
card.delete if card
self.stp_invoice_id = invoice.id
self.invoice.stp_invoice_id = invoice.id
self.invoice.total = invoice.total
self.stp_invoice_id = stp_invoice.id
self.invoice.stp_invoice_id = stp_invoice.id
self.invoice.total = invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+)
save!
rescue Stripe::CardError => card_error
clear_payment_info(card, invoice, invoice_items)
clear_payment_info(card, stp_invoice, invoice_items)
logger.info card_error
errors[:card] << card_error.message
return false
rescue Stripe::InvalidRequestError => e
# Invalid parameters were supplied to Stripe's API
clear_payment_info(card, invoice, invoice_items)
clear_payment_info(card, stp_invoice, invoice_items)
logger.error e
errors[:payment] << e.message
return false
rescue Stripe::AuthenticationError => e
# Authentication with Stripe's API failed
# (maybe you changed API keys recently)
clear_payment_info(card, invoice, invoice_items)
clear_payment_info(card, stp_invoice, invoice_items)
logger.error e
errors[:payment] << e.message
return false
rescue Stripe::APIConnectionError => e
# Network communication with Stripe failed
clear_payment_info(card, invoice, invoice_items)
clear_payment_info(card, stp_invoice, invoice_items)
logger.error e
errors[:payment] << e.message
return false
rescue Stripe::StripeError => e
# Display a very generic error to the user, and maybe send
# yourself an email
clear_payment_info(card, invoice, invoice_items)
clear_payment_info(card, stp_invoice, invoice_items)
logger.error e
errors[:payment] << e.message
return false
rescue => e
# Something else happened, completely unrelated to Stripe
clear_payment_info(card, invoice, invoice_items)
clear_payment_info(card, stp_invoice, invoice_items)
logger.error e
errors[:payment] << e.message
return false
@ -251,6 +262,14 @@ class Reservation < ActiveRecord::Base
def save_with_local_payment
if user.invoicing_disabled?
if valid?
### generate invoice only for calcul price, to refactoring!!
build_invoice(user: user)
generate_invoice_items(true)
@wallet_amount_debit = get_wallet_amount_debit
self.invoice = nil
###
save!
UsersCredits::Manager.new(reservation: self).update_credits
return true
@ -332,4 +351,24 @@ class Reservation < ActiveRecord::Base
end
reservable.update_columns(nb_free_places: nb_free_places)
end
def get_wallet_amount_debit
total = self.invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+) or 0
if plan_id.present?
plan = Plan.find(plan_id)
total += plan.amount
end
wallet_amount = (user.wallet.amount * 100).to_i
return wallet_amount >= total ? total : wallet_amount
end
def debit_user_wallet
if @wallet_amount_debit.present? and @wallet_amount_debit != 0
amount = @wallet_amount_debit / 100.0
wallet_transaction = WalletService.new(user: user, wallet: user.wallet).debit(amount, self)
if !user.invoicing_disabled? and wallet_transaction
self.invoice.update_columns(wallet_amount: @wallet_amount_debit, wallet_transaction_id: wallet_transaction.id)
end
end
end
end

View File

@ -22,7 +22,20 @@ class Subscription < ActiveRecord::Base
if valid?
customer = Stripe::Customer.retrieve(user.stp_customer_id)
begin
new_subscription = customer.subscriptions.create(plan: plan.stp_plan_id, card: card_token)
# dont add a wallet invoice item if pay subscription by reservation
if invoice
@wallet_amount_debit = get_wallet_amount_debit
if @wallet_amount_debit != 0
Stripe::InvoiceItem.create(
customer: user.stp_customer_id,
amount: -@wallet_amount_debit,
currency: Rails.application.secrets.stripe_currency,
description: "wallet -#{@wallet_amount_debit / 100.0}"
)
end
end
new_subscription = customer.subscriptions.create(plan: plan.stp_plan_id, source: card_token)
self.stp_subscription_id = new_subscription.id
self.canceled_at = nil
self.expired_at = Time.at(new_subscription.current_period_end)
@ -32,7 +45,16 @@ class Subscription < ActiveRecord::Base
# generate invoice
stp_invoice = Stripe::Invoice.all(customer: user.stp_customer_id, limit: 1).data.first
generate_invoice(stp_invoice.id).save if invoice
if invoice
invoc = generate_invoice(stp_invoice.id)
# debit wallet
wallet_transaction = debit_user_wallet
if wallet_transaction
invoc.wallet_amount = @wallet_amount_debit
invoc.wallet_transaction_id = wallet_transaction.id
end
invoc.save
end
# cancel subscription after create
cancel
return true
@ -73,12 +95,23 @@ class Subscription < ActiveRecord::Base
def save_with_local_payment(invoice = true)
if valid?
@wallet_amount_debit = get_wallet_amount_debit if invoice
self.stp_subscription_id = nil
self.canceled_at = nil
set_expired_at
save!
UsersCredits::Manager.new(user: self.user).reset_credits if expired_date_changed
generate_invoice.save if invoice
if invoice
invoc = generate_invoice
# debit wallet
wallet_transaction = debit_user_wallet
if wallet_transaction
invoc.wallet_amount = @wallet_amount_debit
invoc.wallet_transaction_id = wallet_transaction.id
end
invoc.save
end
return true
else
return false
@ -209,4 +242,16 @@ class Subscription < ActiveRecord::Base
plan.is_a?(PartnerPlan)
end
def get_wallet_amount_debit
total = plan.amount
wallet_amount = (user.wallet.amount * 100).to_i
return wallet_amount >= total ? total : wallet_amount
end
def debit_user_wallet
if @wallet_amount_debit.present? and @wallet_amount_debit != 0
amount = @wallet_amount_debit / 100.0
return WalletService.new(user: user, wallet: user.wallet).debit(amount, self)
end
end
end

View File

@ -45,12 +45,15 @@ class User < ActiveRecord::Base
has_many :tags, through: :user_tags
accepts_nested_attributes_for :tags, allow_destroy: true
has_one :wallet, dependent: :destroy
# fix for create admin user
before_save do
self.email.downcase! if self.email
end
before_create :assign_default_role
after_create :create_a_wallet
after_commit :create_stripe_customer, on: [:create]
after_commit :notify_admin_when_user_is_created, on: :create
after_update :notify_admin_invoicing_changed, if: :invoicing_disabled_changed?
@ -333,6 +336,10 @@ class User < ActiveRecord::Base
StripeWorker.perform_async(:create_stripe_customer, id)
end
def create_a_wallet
self.create_wallet
end
def notify_admin_when_user_is_created
if need_completion? and not provider.nil?
NotificationCenter.call type: 'notify_admin_when_user_is_imported',

24
app/models/wallet.rb Normal file
View File

@ -0,0 +1,24 @@
class Wallet < ActiveRecord::Base
include AmountConcern
belongs_to :user
has_many :wallet_transactions, dependent: :destroy
validates :user, presence: true
def credit(amount)
if amount.is_a?(Numeric) and amount >= 0
self.amount += amount
return save
end
false
end
def debit(amount)
if amount.is_a?(Numeric) and amount >= 0
self.amount -= amount
return save
end
false
end
end

View File

@ -0,0 +1,12 @@
class WalletTransaction < ActiveRecord::Base
include AmountConcern
belongs_to :user
belongs_to :wallet
belongs_to :reservation
belongs_to :transactable, polymorphic: true
has_one :invoice
validates_inclusion_of :transaction_type, in: %w( credit debit )
validates :user, :wallet, presence: true
end

View File

@ -196,23 +196,41 @@ module PDF
payment_verbose += I18n.t('invoices.by_transfer')
when 'cash'
payment_verbose += I18n.t('invoices.by_cash')
when 'wallet'
payment_verbose += I18n.t('invoices.by_wallet')
when 'none'
payment_verbose = I18n.t('invoices.no_refund')
else
puts "ERROR : specified refunding method (#{payment_verbose}) is unknown"
end
payment_verbose += ' '+I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))
else
if invoice.wallet_amount
wallet_amount = invoice.wallet_amount / 100.0
total = total - wallet_amount
end
if invoice.stp_invoice_id
payment_verbose = I18n.t('invoices.settlement_by_debit_card')
else
payment_verbose = I18n.t('invoices.settlement_done_at_the_reception')
end
end
unless invoice.is_a?(Avoir)
if total == 0 and wallet_amount
payment_verbose = I18n.t('invoices.settlement_by_wallet')
end
payment_verbose += ' '+I18n.t('invoices.on_DATE_at_TIME', DATE: I18n.l(invoice.created_at.to_date), TIME:I18n.l(invoice.created_at, format: :hour_minute))
end
unless invoice.is_a?(Avoir) and invoice.avoir_mode == 'none'
payment_verbose += ' '+I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total)) if invoice.avoir_mode != 'none'
if total > 0 or !invoice.wallet_amount
payment_verbose += ' '+I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(total))
end
if invoice.wallet_amount
if total > 0
payment_verbose += ' '+I18n.t('invoices.and') + ' ' + I18n.t('invoices.by_wallet') + ' ' + I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))
else
payment_verbose += ' '+I18n.t('invoices.for_an_amount_of_AMOUNT', AMOUNT: number_to_currency(wallet_amount))
end
end
end
text payment_verbose

View File

@ -0,0 +1,13 @@
class WalletPolicy < ApplicationPolicy
def by_user?
user.is_admin? or user == record.user
end
def transactions?
user.is_admin? or user == record.user
end
def credit?
user.is_admin?
end
end

View File

@ -0,0 +1,40 @@
class WalletService
def initialize(user: nil, wallet: nil)
@user = user
@wallet = wallet
end
## credit an amount to wallet, if credit success then return a wallet transaction and notify to admin
def credit(amount)
ActiveRecord::Base.transaction do
if @wallet.credit(amount)
transaction = WalletTransaction.new(user: @user, wallet: @wallet, transaction_type: 'credit', amount: amount)
if transaction.save
NotificationCenter.call type: 'notify_user_wallet_is_credited',
receiver: @wallet.user,
attached_object: transaction
NotificationCenter.call type: 'notify_admin_user_wallet_is_credited',
receiver: User.admins,
attached_object: transaction
return transaction
end
end
raise ActiveRecord::Rollback
end
return false
end
## debit an amount to wallet, if debit success then return a wallet transaction
def debit(amount, transactable)
ActiveRecord::Base.transaction do
if @wallet.debit(amount)
transaction = WalletTransaction.new(user: @user, wallet: @wallet, transaction_type: 'debit', amount: amount, transactable: transactable)
if transaction.save
return transaction
end
end
raise ActiveRecord::Rollback
end
return false
end
end

View File

@ -0,0 +1,7 @@
json.title notification.notification_type
amount = notification.attached_object.amount
json.description t('.wallet_is_credited',
AMOUNT: number_to_currency(amount),
USER: notification.attached_object.wallet.user.profile.full_name,
ADMIN: notification.attached_object.user.profile.full_name)
json.url notification_url(notification, format: :json)

View File

@ -0,0 +1,5 @@
json.title notification.notification_type
amount = notification.attached_object.amount
json.description t('.your_wallet_is_credited',
AMOUNT: number_to_currency(amount))
json.url notification_url(notification, format: :json)

View File

@ -0,0 +1 @@
json.extract! @wallet, :id, :user_id, :amount

View File

@ -0,0 +1,11 @@
json.array!(@wallet_transactions) do |t|
json.extract! t, :id, :transaction_type, :created_at, :amount, :transactable_type
json.user do
json.id t.user.id
json.full_name t.user.profile.full_name
end
json.invoice do
json.id t.invoice.id
json.reference t.invoice.reference
end if t.invoice
end

View File

@ -0,0 +1,9 @@
<%# this is a mail template of notifcation notify_admin_user_wallet_is_credited %>
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p>
<%= t('.body.wallet_credit_html',
AMOUNT: number_to_currency(@attached_object.amount),
USER: @attached_object.wallet.user.profile.full_name,
ADMIN: @attached_object.user.profile.full_name)
%>
</p>

View File

@ -0,0 +1,2 @@
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
<p><%= t('.body.wallet_credit_html', AMOUNT: number_to_currency(@attached_object.amount)) %></p>

View File

@ -201,6 +201,7 @@ en:
day: "Day"
"#_of_invoice": "# of invoice"
online_sales: "Online sales"
wallet: "Wallet"
refund: "Refund"
documentation: "Documentation"
2_digits_year_(eg_70): "2 digits year (eg. 70)"
@ -224,6 +225,8 @@ en:
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Add a notice regarding refunds, only if the invoice is concerned."
this_will_never_be_added_when_an_online_sales_notice_is_present: "This will never be added when an online sales notice is present."
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ed. R[/A] will add "/A" to the refund invoices)'
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Add a notice regarding the wallet, only if the invoice is concerned."
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(eg. W[/PM] will add "/PM" to the invoices settled with wallet)'
code: "Code"
enable_the_code: "Enable the code"
enabled: "Enabled"
@ -246,6 +249,7 @@ en:
by_cash: "By cash"
by_cheque: "By cheque"
by_transfer: "By transfer"
by_wallet: "By wallet"
you_must_select_at_least_one_element_to_create_a_refund: "You must select at least one element, to create a refund."
unable_to_create_the_refund: "Unable to create the refund"
invoice_reference_successfully_saved: "Invoice reference successfully saved."

View File

@ -201,6 +201,7 @@ fr:
day: "Jour"
"#_of_invoice": "N° de facture"
online_sales: "Vente en ligne"
wallet: "Porte-monnaie"
refund: "Remboursement"
documentation: "Documentation"
2_digits_year_(eg_70): "Année sur 2 chiffres (ex. 70)"
@ -224,6 +225,8 @@ fr:
add_a_notice_regarding_refunds_only_if_the_invoice_is_concerned: "Ajoute une information relative aux remboursements, uniquement si cela concerne la facture. "
this_will_never_be_added_when_an_online_sales_notice_is_present: "Ceci ne sera jamais cumulé avec une information de vente en ligne."
(eg_R[/A]_will_add_/A_to_the_refund_invoices): '(ex. R[/A] ajoutera "/A" aux factures de remboursement)'
add_a_notice_regarding_the_wallet_only_if_the_invoice_is_concerned: "Ajoute une information relative au paiement par le porte-monnaie, uniquement si cela concerne la facture."
(eg_W[/PM]_will_add_/PM_to_the_invoices_settled_with_wallet): '(ex. W[/PM] ajoutera "/PM" aux factures réglées avec porte-monnaie)'
code: "Code"
enable_the_code: "Activer le code"
enabled: "Activé"
@ -246,6 +249,7 @@ fr:
by_cash: "En espèces"
by_cheque: "Par chèque"
by_transfer: "Par virement"
by_wallet: "Par porte-monnaie"
you_must_select_at_least_one_element_to_create_a_refund: "Vous devez sélectionner au moins un élément sur lequel créer un avoir."
unable_to_create_the_refund: "Impossible de créer l'avoir"
invoice_reference_successfully_saved: "La référence facture a bien été enregistrée."

View File

@ -14,6 +14,7 @@ en:
my_trainings: "My Trainings"
my_events: "My Events"
my_invoices: "My Invoices"
my_wallet: "My Wallet"
# login/logout
sign_out: "Sign Out"

View File

@ -14,6 +14,7 @@ fr:
my_trainings: "Mes formations"
my_events: "Mes évènements"
my_invoices: "Mes factures"
my_wallet: "Mon porte-monnaie"
# connexion / déconnexion
sign_out: "Se déconnecter"

View File

@ -160,11 +160,14 @@ en:
_the_general_terms_and_conditions: "the general terms and conditions."
enter_your_card_number: "Enter your card number"
confirm_my_payment_of_: "Confirm my payment of" # context: confirm my payment of $20.00
credit_amount_for_pay_reservation: "{{amount}} {{currency}} remains to be paid to confirm your reservation"
client_credit_amount_for_pay_reservation: "{{amount}} {{currency}} remains to be paid to confirm reservation of client"
valid_reservation_modal:
# dialog of on site payment for reservations
booking_confirmation: "Booking confirmation"
here_is_the_summary_of_the_slots_to_book_for_the_current_user: "Here is the summary of the slots to book for the current user:"
confirm_client_payment_of_: "Confirm (Payment on site) of {{amount}} {{currency}}"
event:
# event edition form
@ -295,3 +298,29 @@ en:
author: "Author"
collaborator: "Collaborator"
private_profile: "Private profile"
wallet:
wallet: 'Wallet'
your_wallet_amount: 'Your amount available'
wallet_amount: 'Amount available'
no_transactions_for_now: 'No transactions for now'
operation: 'Operation'
operator: 'Operator'
amount: 'Amount'
credit: 'Credit'
debit: 'Debit'
credit_title: 'Credit wallet'
credit_label: 'Set the amount to be credited'
to_credit: 'Credit'
wallet_credit_successfully: "Wallet of user is credited successfully."
a_problem_occurred_for_wallet_credit: "A problem is occurred while taking the credit of wallet"
amount_is_required: "The amount is required"
amount_minimum_1: "The amount minimum is 1"
you_have_amount_in_wallet: "You have {{amount}} {{currency}} in your wallet"
client_have_amount_in_wallet: "Client has {{amount}} {{currency}} in wallet"
wallet_pay_reservation: "You can pay direct your reservation"
client_wallet_pay_reservation: "Client can pay direct reservation"
debit_subscription: "Debit by subscription"
debit_reservation_training: "Debit by reservation of training"
debit_reservation_machine: "Debit by reservation of machine"
debit_reservation_event: "Debit by reservation of event"

View File

@ -160,11 +160,14 @@ fr:
_the_general_terms_and_conditions: "les conditions générales de vente."
enter_your_card_number: "Saisissez votre numéro de carte"
confirm_my_payment_of_: "Valider mon paiement de" # contexte : valider mon paiement de 20,00 €
credit_amount_for_pay_reservation: "Il vous reste {{amount}} {{currency}} à payer pour valider votre réservation"
client_credit_amount_for_pay_reservation: "Il reste {{amount}} {{currency}} à payer pour valider la réservation"
valid_reservation_modal:
# fenêtre de paiement sur place d'une réservation
booking_confirmation: "Validation réservation"
here_is_the_summary_of_the_slots_to_book_for_the_current_user: "Voici le récapitulatif des créneaux à réserver pour l'utilisateur courant :"
confirm_client_payment_of_: "Valider (Paiement sur place) de {{amount}} {{currency}}"
event:
# formulaire d'édition d'un événement
@ -295,3 +298,29 @@ fr:
author: "Auteur"
collaborator: "Collaborateur"
private_profile: "Profil privé"
wallet:
wallet: 'Porte-monnaie'
your_wallet_amount: 'Votre montant disponible'
wallet_amount: 'Montant disponible'
no_transactions_for_now: 'Aucune transaction pour le moment'
operation: 'Opération'
operator: 'Opérateur'
amount: 'Montant'
credit: 'Crédit'
debit: 'Débit'
credit_title: 'Créditer le porte-monnaie'
credit_label: 'Indiquez le montant à créditer'
to_credit: 'Créditer'
wallet_credit_successfully: "Le porte-monnaie d'utilisateur a été chargé avec succès."
a_problem_occurred_for_wallet_credit: "Un problème est survenu lors du chargement du porte-monnaie."
amount_is_required: "Le montant est obligatoire"
amount_minimum_1: "Le montant minimum est d'1"
you_have_amount_in_wallet: "Vous avez {{amount}} {{currency}} sur votre porte-monnaie"
client_have_amount_in_wallet: "Le client a {{amount}} {{currency}} sur son porte-monnaie"
wallet_pay_reservation: "Vous pouvez effectuer directement votre paiement de réservation"
client_wallet_pay_reservation: "Le client pouvez effectuer directement son paiement de réservation"
debit_subscription: "Payer un abonnement"
debit_reservation_training: "Payer un reservation de formation"
debit_reservation_machine: "Payer un reservation de machine"
debit_reservation_event: "Payer un reservation d'évenement"

View File

@ -97,14 +97,17 @@ en:
by_transfer: "by transfer"
by_cash: "by cash"
no_refund: "No refund"
by_wallet: "by wallet"
settlement_by_debit_card: "Settlement by debit card"
settlement_done_at_the_reception: "Settlement done at the reception"
settlement_by_wallet: "Settlement by wallet"
on_DATE_at_TIME: "on %{DATE} at %{TIME},"
for_an_amount_of_AMOUNT: "for an amount of %{AMOUNT}"
on_DATE_from_START_to_END: "On %{DATE} from %{START} to %{END}" # eg: on feb. 7 from 7AM to 9AM
from_STARTDATE_to_ENDDATE_from_STARTTIME_to_ENDTIME: "From %{STARTDATE} to %{ENDDATE}, from %{STARTTIME} to %{ENDTIME}" # eg: from feb. 7 to feb. 10, from 6PM to 10PM
subscription_of_NAME_for_DURATION_starting_from_DATE: "Subscription of %{NAME} for %{DURATION} starting from %{DATE}"
subscription_of_NAME_extended_starting_from_STARTDATE_until_ENDDATE: "Subscription of %{NAME} extended (Free days) starting from %{STARTDATE} until %{ENDDATE}"
and: 'and'
trainings:
# training availabilities
@ -229,6 +232,10 @@ en:
undefined_notification:
unknown_notification: "Unknown notification"
notification_ID_wrong_type_TYPE_unknown: "Notification %{ID} wrong (type %{TYPE} unknown)"
notify_user_wallet_is_credited:
your_wallet_is_credited: "Your wallet has been credited by administrator"
notify_admin_user_wallet_is_credited:
wallet_is_credited: "The wallet of member %{USER} has been credited %{AMOUNT}"
statistics:
# statistics tools for admins

View File

@ -96,15 +96,18 @@ fr:
by_cheque: "par chèque"
by_transfer: "par virement"
by_cash: "en espèces"
by_wallet: "par porte-monnaie"
no_refund: "Pas de remboursement"
settlement_by_debit_card: "Règlement effectué par carte bancaire"
settlement_done_at_the_reception: "Règlement effectué à l'accueil"
settlement_by_wallet: "Règlement effectué par porte-monnaie"
on_DATE_at_TIME: "le %{DATE} à %{TIME},"
for_an_amount_of_AMOUNT: "pour un montant de %{AMOUNT}"
on_DATE_from_START_to_END: "Le %{DATE} de %{START} à %{END}" # eg: on feb. 7 from 7AM to 9AM
from_STARTDATE_to_ENDDATE_from_STARTTIME_to_ENDTIME: "Du %{STARTDATE} au %{ENDDATE}, de %{STARTTIME} à %{ENDTIME}" # eg: from feb. 7 to feb. 10, from 6PM to 10PM
subscription_of_NAME_for_DURATION_starting_from_DATE: "Abonnement de %{NAME} pour %{DURATION} à compter du %{DATE}"
subscription_of_NAME_extended_starting_from_STARTDATE_until_ENDDATE: "Prolongement Abonnement (Jours gratuits) de %{NAME} à compter du %{STARTDATE} jusqu'au %{ENDDATE}"
and: 'et'
trainings:
# disponibilités formations
@ -229,6 +232,10 @@ fr:
undefined_notification:
unknown_notification: "Notification inconnue"
notification_ID_wrong_type_TYPE_unknown: "Notification {ID} erronée (type {TYPE} inconnu)."
notify_user_wallet_is_credited:
your_wallet_is_credited: "Votre porte-monnaie a bien été crédité de %{AMOUNT} par l'administrateur"
notify_admin_user_wallet_is_credited:
wallet_is_credited: "Le porte-monnaie du membre %{USER} a bien été crédité de %{AMOUNT}"
statistics:
# outil de statistiques pour les administrateurs

View File

@ -240,5 +240,15 @@ en:
disabled: "From now on, no invoice will be issued when the user pays at the reception."
enabled: "From now on, all payments made by this user at the reception will lead to invoicing issuing. "
notify_user_wallet_is_credited:
subject: "Your wallet has been credited"
body:
wallet_credit_html: "Your wallet has been credited %{AMOUNT} by administrator."
notify_admin_user_wallet_is_credited:
subject: "The wallet of an user has been credited"
body:
wallet_credit_html: "The wallet of member %{USER} has been credited %{AMOUNT} by administrator %{ADMIN}."
shared:
hello: "Hello %{user_name}"

View File

@ -240,5 +240,15 @@ fr:
disabled: "Désormais, aucune facture ne sera générée pour les paiement de cet utilisateur effectués à l'accueil."
enabled: "Désormais, tous les paiement de cet utilisateur effectués à l'accueil, donneront lieu à la génération d'une facture."
notify_user_wallet_is_credited:
subject: "Votre porte-monnaie a bien été crédité"
body:
wallet_credit_html: "Votre porte-monnaie a bien été crédité de %{AMOUNT} par l'adminitrateur."
notify_admin_user_wallet_is_credited:
subject: "Le porte-monnaie d'un utilisateur a bien été crédité"
body:
wallet_credit_html: "Le porte-monnaie du membre %{USER} a bien été crédité de %{AMOUNT} par l'adminitrateur %{ADMIN}."
shared:
hello: "Bonjour %{user_name}"

View File

@ -48,6 +48,11 @@ Rails.application.routes.draw do
resources :notifications, only: [:index, :show, :update] do
match :update_all, path: '/', via: [:put, :patch], on: :collection
end
resources :wallet, only: [] do
get '/by_user/:user_id', action: 'by_user', on: :collection
get :transactions, on: :member
put :credit, on: :member
end
# for homepage
get '/last_subscribed/:last' => "members#last_subscribed"

View File

@ -0,0 +1,18 @@
class CreateWallets < ActiveRecord::Migration
def up
create_table :wallets do |t|
t.belongs_to :user, index: true, foreign_key: true
t.integer :amount, default: 0
t.timestamps null: false
end
User.all.each do |u|
Wallet.create(user: u)
end
end
def down
drop_table :wallets
end
end

View File

@ -0,0 +1,13 @@
class CreateWalletTransactions < ActiveRecord::Migration
def change
create_table :wallet_transactions do |t|
t.belongs_to :user, index: true, foreign_key: true
t.belongs_to :wallet, index: true, foreign_key: true
t.references :transactable, polymorphic: true, index: {name: 'index_wallet_transactions_on_transactable'}
t.string :transaction_type
t.integer :amount
t.timestamps null: false
end
end
end

View File

@ -0,0 +1,5 @@
class AddWalletAmountToInvoice < ActiveRecord::Migration
def change
add_column :invoices, :wallet_amount, :integer
end
end

View File

@ -0,0 +1,5 @@
class AddWalletTransactionToInvoice < ActiveRecord::Migration
def change
add_reference :invoices, :wallet_transaction, index: true, foreign_key: true
end
end

View File

@ -11,7 +11,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 20160714095018) do
ActiveRecord::Schema.define(version: 20160720124355) do
# These are extensions that must be enabled in order to support this database
enable_extension "plpgsql"
@ -220,10 +220,13 @@ ActiveRecord::Schema.define(version: 20160714095018) do
t.string "type", limit: 255
t.boolean "subscription_to_expire"
t.text "description"
t.integer "wallet_amount"
t.integer "wallet_transaction_id"
end
add_index "invoices", ["invoice_id"], name: "index_invoices_on_invoice_id", using: :btree
add_index "invoices", ["user_id"], name: "index_invoices_on_user_id", using: :btree
add_index "invoices", ["wallet_transaction_id"], name: "index_invoices_on_wallet_transaction_id", using: :btree
create_table "licences", force: :cascade do |t|
t.string "name", limit: 255, null: false
@ -708,14 +711,42 @@ ActiveRecord::Schema.define(version: 20160714095018) do
add_index "users_roles", ["user_id", "role_id"], name: "index_users_roles_on_user_id_and_role_id", using: :btree
create_table "wallet_transactions", force: :cascade do |t|
t.integer "user_id"
t.integer "wallet_id"
t.integer "transactable_id"
t.string "transactable_type"
t.string "transaction_type"
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "wallet_transactions", ["transactable_type", "transactable_id"], name: "index_wallet_transactions_on_transactable", using: :btree
add_index "wallet_transactions", ["user_id"], name: "index_wallet_transactions_on_user_id", using: :btree
add_index "wallet_transactions", ["wallet_id"], name: "index_wallet_transactions_on_wallet_id", using: :btree
create_table "wallets", force: :cascade do |t|
t.integer "user_id"
t.integer "amount", default: 0
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
add_index "wallets", ["user_id"], name: "index_wallets_on_user_id", using: :btree
add_foreign_key "availability_tags", "availabilities"
add_foreign_key "availability_tags", "tags"
add_foreign_key "events_event_themes", "event_themes"
add_foreign_key "events_event_themes", "events"
add_foreign_key "invoices", "wallet_transactions"
add_foreign_key "o_auth2_mappings", "o_auth2_providers"
add_foreign_key "open_api_calls_count_tracings", "open_api_clients"
add_foreign_key "prices", "groups"
add_foreign_key "prices", "plans"
add_foreign_key "user_tags", "tags"
add_foreign_key "user_tags", "users"
add_foreign_key "wallet_transactions", "users"
add_foreign_key "wallet_transactions", "wallets"
add_foreign_key "wallets", "users"
end

7
test/fixtures/wallet_transactions.yml vendored Normal file
View File

@ -0,0 +1,7 @@
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
transaction1:
user_id: 5
wallet: wallet_5
transaction_type: credit
amount: 1000

27
test/fixtures/wallets.yml vendored Normal file
View File

@ -0,0 +1,27 @@
wallet_2:
user_id: 2
amount: 0
wallet_4:
user_id: 4
amount: 0
wallet_6:
user_id: 6
amount: 0
wallet_5:
user_id: 5
amount: 1000
wallet_3:
user_id: 3
amount: 0
wallet_1:
user_id: 1
amount: 0
wallet_7:
user_id: 7
amount: 0

View File

@ -69,7 +69,7 @@ class EventsTest < ActionDispatch::IntegrationTest
reservable_type: 'Event',
nb_reserve_places: 2,
nb_reserve_reduced_places: 0,
slot_attributes: [
slots_attributes: [
{
start_at: e.availability.start_at,
end_at: e.availability.end_at,
@ -114,4 +114,4 @@ class EventsTest < ActionDispatch::IntegrationTest
assert_equal 20, e.nb_total_places, 'Total number of places was not updated'
assert_equal 18, e.nb_free_places, 'Number of free places was not updated'
end
end
end

View File

@ -220,5 +220,174 @@ module Reservations
# notification
assert_not_empty Notification.where(attached_object: reservation)
end
test "user without subscription reserves a machine and pay by wallet with success" do
@vlonchamp = User.find_by(username: 'vlonchamp')
machine = Machine.find(6)
availability = machine.availabilities.first
reservations_count = Reservation.count
invoice_count = Invoice.count
invoice_items_count = InvoiceItem.count
users_credit_count = UsersCredit.count
post reservations_path, { reservation: {
user_id: @vlonchamp.id,
reservable_id: machine.id,
reservable_type: machine.class.name,
slots_attributes: [
{ start_at: availability.start_at.to_s(:iso8601),
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
}
]
}}.to_json, default_headers
# general assertions
assert_equal 201, response.status
assert_equal reservations_count + 1, Reservation.count
assert_equal invoice_count + 1, Invoice.count
assert_equal invoice_items_count + 1, InvoiceItem.count
assert_equal users_credit_count, UsersCredit.count
# reservation assertions
reservation = Reservation.last
assert reservation.invoice
assert reservation.stp_invoice_id.blank?
assert_equal 1, reservation.invoice.invoice_items.count
# invoice assertions
invoice = reservation.invoice
assert invoice.stp_invoice_id.blank?
refute invoice.total.blank?
# invoice_items assertions
invoice_item = InvoiceItem.last
refute invoice_item.stp_invoice_item_id
assert_equal invoice_item.amount, machine.prices.find_by(group_id: @vlonchamp.group_id, plan_id: nil).amount
# invoice assertions
invoice = Invoice.find_by(invoiced: reservation)
assert_invoice_pdf invoice
# notification
assert_not_empty Notification.where(attached_object: reservation)
# wallet
assert_equal @vlonchamp.wallet.amount, 0
assert_equal @vlonchamp.wallet.wallet_transactions.count, 2
transaction = @vlonchamp.wallet.wallet_transactions.last
assert_equal transaction.transaction_type, 'debit'
assert_equal transaction.amount, 10
assert_equal transaction.amount, invoice.wallet_amount / 100.0
assert_equal transaction.id, invoice.wallet_transaction_id
end
test "user reserves a machine and plan pay by wallet with success" do
@vlonchamp = User.find_by(username: 'vlonchamp')
machine = Machine.find(6)
availability = machine.availabilities.first
plan = Plan.find_by(group_id: @vlonchamp.group.id, type: 'Plan', base_name: 'Mensuel tarif réduit')
reservations_count = Reservation.count
invoice_count = Invoice.count
invoice_items_count = InvoiceItem.count
users_credit_count = UsersCredit.count
wallet_transactions_count = WalletTransaction.count
post reservations_path, { reservation: {
user_id: @vlonchamp.id,
reservable_id: machine.id,
reservable_type: machine.class.name,
plan_id: plan.id,
slots_attributes: [
{ start_at: availability.start_at.to_s(:iso8601),
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
}
]
}}.to_json, default_headers
# general assertions
assert_equal 201, response.status
assert_equal reservations_count + 1, Reservation.count
assert_equal invoice_count + 1, Invoice.count
assert_equal invoice_items_count + 2, InvoiceItem.count
assert_equal users_credit_count + 1, UsersCredit.count
assert_equal wallet_transactions_count + 1, WalletTransaction.count
# reservation assertions
reservation = Reservation.last
assert reservation.invoice
assert reservation.stp_invoice_id.blank?
assert_equal 2, reservation.invoice.invoice_items.count
# invoice assertions
invoice = reservation.invoice
assert invoice.stp_invoice_id.blank?
refute invoice.total.blank?
assert_equal invoice.total, 2000
# invoice assertions
invoice = Invoice.find_by(invoiced: reservation)
assert_invoice_pdf invoice
# notification
assert_not_empty Notification.where(attached_object: reservation)
# wallet
assert_equal @vlonchamp.wallet.amount, 0
assert_equal @vlonchamp.wallet.wallet_transactions.count, 2
transaction = @vlonchamp.wallet.wallet_transactions.last
assert_equal transaction.transaction_type, 'debit'
assert_equal transaction.amount, 10
assert_equal transaction.amount, invoice.wallet_amount / 100.0
assert_equal transaction.id, invoice.wallet_transaction_id
end
test "user without subscription and with invoicing disabled reserves a machine and pay wallet with success" do
@vlonchamp = User.find_by(username: 'vlonchamp')
@vlonchamp.update!(invoicing_disabled: true)
machine = Machine.find(6)
availability = machine.availabilities.first
reservations_count = Reservation.count
invoice_count = Invoice.count
invoice_items_count = InvoiceItem.count
users_credit_count = UsersCredit.count
post reservations_path, { reservation: {
user_id: @vlonchamp.id,
reservable_id: machine.id,
reservable_type: machine.class.name,
slots_attributes: [
{ start_at: availability.start_at.to_s(:iso8601),
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
}
]
}}.to_json, default_headers
# general assertions
assert_equal 201, response.status
assert_equal reservations_count + 1, Reservation.count
assert_equal invoice_count, Invoice.count
assert_equal invoice_items_count, InvoiceItem.count
assert_equal users_credit_count, UsersCredit.count
# reservation assertions
reservation = Reservation.last
refute reservation.invoice
assert reservation.stp_invoice_id.blank?
# notification
assert_not_empty Notification.where(attached_object: reservation)
end
end
end

View File

@ -292,5 +292,143 @@ module Reservations
# check that user subscription were extended
assert_equal reservation.slots.first.start_at + plan.duration, @user_with_subscription.subscription.expired_at
end
test "user reserves a machine and pay by wallet with success" do
@vlonchamp = User.find_by(username: 'vlonchamp')
login_as(@vlonchamp, scope: :user)
machine = Machine.find(6)
availability = machine.availabilities.first
reservations_count = Reservation.count
invoice_count = Invoice.count
invoice_items_count = InvoiceItem.count
users_credit_count = UsersCredit.count
wallet_transactions_count = WalletTransaction.count
VCR.use_cassette("reservations_create_for_machine_and_pay_wallet_success") do
post reservations_path, { reservation: {
user_id: @vlonchamp.id,
reservable_id: machine.id,
reservable_type: machine.class.name,
card_token: stripe_card_token,
slots_attributes: [
{ start_at: availability.start_at.to_s(:iso8601),
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
availability_id: availability.id
}
]
}}.to_json, default_headers
end
# general assertions
assert_equal 201, response.status
assert_equal reservations_count + 1, Reservation.count
assert_equal invoice_count + 1, Invoice.count
assert_equal invoice_items_count + 1, InvoiceItem.count
assert_equal users_credit_count, UsersCredit.count
assert_equal wallet_transactions_count + 1, WalletTransaction.count
# reservation assertions
reservation = Reservation.last
assert reservation.invoice
refute reservation.stp_invoice_id.blank?
assert_equal 1, reservation.invoice.invoice_items.count
# invoice assertions
invoice = reservation.invoice
refute invoice.stp_invoice_id.blank?
refute invoice.total.blank?
# invoice_items assertions
invoice_item = InvoiceItem.last
assert invoice_item.stp_invoice_item_id
assert_equal invoice_item.amount, machine.prices.find_by(group_id: @vlonchamp.group_id, plan_id: nil).amount
# invoice assertions
invoice = Invoice.find_by(invoiced: reservation)
assert_invoice_pdf invoice
# notification
assert_not_empty Notification.where(attached_object: reservation)
# wallet
assert_equal @vlonchamp.wallet.amount, 0
assert_equal @vlonchamp.wallet.wallet_transactions.count, 2
transaction = @vlonchamp.wallet.wallet_transactions.last
assert_equal transaction.transaction_type, 'debit'
assert_equal transaction.amount, 10
assert_equal transaction.amount, invoice.wallet_amount / 100.0
end
test "user reserves a training and plan by wallet with success" do
@vlonchamp = User.find_by(username: 'vlonchamp')
login_as(@vlonchamp, scope: :user)
training = Training.first
availability = training.availabilities.first
plan = Plan.find_by(group_id: @vlonchamp.group.id, type: 'Plan', base_name: 'Mensuel tarif réduit')
reservations_count = Reservation.count
invoice_count = Invoice.count
invoice_items_count = InvoiceItem.count
wallet_transactions_count = WalletTransaction.count
VCR.use_cassette("reservations_create_for_training_and_plan_by_pay_wallet_success") do
post reservations_path, { reservation: {
user_id: @user_without_subscription.id,
reservable_id: training.id,
reservable_type: training.class.name,
card_token: stripe_card_token,
plan_id: plan.id,
slots_attributes: [
{
start_at: availability.start_at.to_s(:iso8601),
end_at: availability.end_at.to_s(:iso8601),
availability_id: availability.id
}
]
}}.to_json, default_headers
end
# general assertions
assert_equal 201, response.status
assert_equal reservations_count + 1, Reservation.count
assert_equal invoice_count + 1, Invoice.count
assert_equal invoice_items_count + 2, InvoiceItem.count
assert_equal wallet_transactions_count + 1, WalletTransaction.count
# reservation assertions
reservation = Reservation.last
assert reservation.invoice
refute reservation.stp_invoice_id.blank?
assert_equal 2, reservation.invoice.invoice_items.count
# invoice assertions
invoice = reservation.invoice
refute invoice.stp_invoice_id.blank?
refute invoice.total.blank?
assert_equal invoice.total, 2000
# invoice assertions
invoice = Invoice.find_by(invoiced: reservation)
assert_invoice_pdf invoice
# notification
assert_not_empty Notification.where(attached_object: reservation)
# wallet
assert_equal @vlonchamp.wallet.amount, 0
assert_equal @vlonchamp.wallet.wallet_transactions.count, 2
transaction = @vlonchamp.wallet.wallet_transactions.last
assert_equal transaction.transaction_type, 'debit'
assert_equal transaction.amount, 10
assert_equal transaction.amount, invoice.wallet_amount / 100.0
end
end
end

View File

@ -83,4 +83,64 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
assert_nil @user.subscription, "user's subscription was found"
end
end
test 'user successfully takes a subscription with wallet' do
@vlonchamp = User.find_by(username: 'vlonchamp')
login_as(@vlonchamp, scope: :user)
plan = Plan.find_by(group_id: @vlonchamp.group.id, type: 'Plan', base_name: 'Mensuel tarif réduit')
VCR.use_cassette("subscriptions_user_create_success_with_wallet") do
post '/api/subscriptions',
{
subscription: {
plan_id: plan.id,
user_id: @vlonchamp.id,
card_token: stripe_card_token
}
}.to_json, default_headers
end
# Check response format & status
assert_equal 201, response.status, response.body
assert_equal Mime::JSON, response.content_type
# Check the correct plan was subscribed
subscription = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match'
# Check that the user has the correct subscription
assert_not_nil @vlonchamp.subscription, "user's subscription was not found"
assert_not_nil @vlonchamp.subscription.plan, "user's subscribed plan was not found"
assert_equal plan.id, @vlonchamp.subscription.plan_id, "user's plan does not match"
# Check that the training credits were set correctly
assert_empty @vlonchamp.training_credits, 'training credits were not reset'
assert_equal @vlonchamp.subscription.plan.training_credit_nb, plan.training_credit_nb, 'trainings credits were not allocated'
# Check that the user benefit from prices of his plan
printer = Machine.find_by_slug('imprimante-3d')
assert_equal 10, (printer.prices.find_by(group_id: @vlonchamp.group_id, plan_id: @vlonchamp.subscription.plan_id).amount / 100), 'machine hourly price does not match'
# Check notifications were sent for every admins
notifications = Notification.where(notification_type_id: NotificationType.find_by_name('notify_admin_subscribed_plan'), attached_object_type: 'Subscription', attached_object_id: subscription[:id])
assert_not_empty notifications, 'no notifications were created'
notified_users_ids = notifications.map {|n| n.receiver_id }
User.admins.each do |adm|
assert_includes notified_users_ids, adm.id, "Admin #{adm.id} was not notified"
end
# Check generated invoice
invoice = Invoice.find_by(invoiced_type: 'Subscription', invoiced_id: subscription[:id])
assert_invoice_pdf invoice
assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription'
# wallet
assert_equal @vlonchamp.wallet.amount, 0
assert_equal @vlonchamp.wallet.wallet_transactions.count, 2
transaction = @vlonchamp.wallet.wallet_transactions.last
assert_equal transaction.transaction_type, 'debit'
assert_equal transaction.amount, 10
assert_equal transaction.amount, invoice.wallet_amount / 100.0
assert_equal transaction.id, invoice.wallet_transaction_id
end
end

View File

@ -0,0 +1,78 @@
class WalletsTest < ActionDispatch::IntegrationTest
# Called before every test method runs. Can be used
# to set up fixture information.
def setup
@vlonchamp = User.find_by(username: 'vlonchamp')
login_as(@vlonchamp, scope: :user)
end
# Called after every test method runs. Can be used to tear
# down fixture information.
def teardown
# Do nothing
end
test 'get my wallet' do
get "/api/wallet/by_user/#{@vlonchamp.id}"
assert_equal 200, response.status
assert_equal Mime::JSON, response.content_type
wallet = json_response(response.body)
assert_equal @vlonchamp.wallet.user_id, wallet[:user_id]
assert_equal @vlonchamp.wallet.amount, wallet[:amount]
end
test 'admin can get wallet by user id' do
@admin = User.find_by_username('admin')
login_as(@admin, scope: :user)
@user1 = User.first
get "/api/wallet/by_user/#{@user1.id}"
assert_equal 200, response.status
assert_equal Mime::JSON, response.content_type
wallet = json_response(response.body)
assert_equal @user1.wallet.user_id, wallet[:user_id]
assert_equal @user1.wallet.amount, wallet[:amount]
end
test 'cant get wallet of an user if not admin' do
user5 = users(:user_4)
get "/api/wallet/by_user/#{user5.id}"
assert_equal 403, response.status
end
test 'get all transactions of wallet' do
w = @vlonchamp.wallet
get "/api/wallet/#{w.id}/transactions"
assert_equal 200, response.status
assert_equal Mime::JSON, response.content_type
transactions = json_response(response.body)
assert_equal w.wallet_transactions.count, transactions.size
assert_equal wallet_transactions(:transaction1).id, transactions.first[:id]
end
test 'only admin and wallet owner can show their transactions' do
user5 = users(:user_4)
get "/api/wallet/#{user5.wallet.id}/transactions"
assert_equal 403, response.status
end
test 'admin can credit amount to a wallet' do
admin = users(:user_1)
login_as(admin, scope: :user)
w = @vlonchamp.wallet
amount = 10.5
expected_amount = w.amount + amount
put "/api/wallet/#{w.id}/credit",
{
amount: amount
}
assert_equal 200, response.status
assert_equal Mime::JSON, response.content_type
wallet = json_response(response.body)
w.reload
assert_equal w.amount, expected_amount
assert_equal w.amount, wallet[:amount]
end
end

9
test/models/user_test.rb Normal file
View File

@ -0,0 +1,9 @@
require 'test_helper'
class UserTest < ActiveSupport::TestCase
test "must create a wallet after create user" do
u = User.create(username: 'user', email: 'userwallet@fabmanager.com', password: 'testpassword', password_confirmation: 'testpassword',
profile_attributes: {first_name: 'user', last_name: 'wallet', gender: true, birthday: 18.years.ago, phone: '0123456789'} )
assert u.wallet.present?
end
end

View File

@ -0,0 +1,39 @@
require 'test_helper'
class WalletTest < ActiveSupport::TestCase
test "default amount must be zero" do
w = Wallet.new
assert w.amount == 0
end
test 'should user present' do
w = Wallet.create
assert w.errors[:user].present?
end
test 'can credit amount' do
w = Wallet.first
expected_amount = w.amount + 5.5
assert w.credit(5.5)
assert_equal w.amount, expected_amount
end
test 'can debit amount' do
w = Wallet.first
w.credit(5)
expected_amount = w.amount - 5
assert w.debit(5)
assert_equal w.amount, expected_amount
end
test 'cant debit/credit a negative' do
w = Wallet.new
assert_not w.credit(-5)
assert_not w.debit(-5)
end
test 'wallet amount cant < 0 after debit' do
w = Wallet.new
assert_not w.debit(5)
end
end

View File

@ -0,0 +1,15 @@
require 'test_helper'
class WalletTransactionTest < ActiveSupport::TestCase
test 'transaction type must be credit or debit' do
@jdupond = User.find_by(username: 'jdupond')
@jdupond_wallet = @jdupond.wallet
transaction = WalletTransaction.new amount: 5, user: @jdupond, wallet: @jdupond_wallet
transaction.transaction_type = 'credit'
assert transaction.valid?
transaction.transaction_type = 'debit'
assert transaction.valid?
transaction.transaction_type = 'other'
assert_not transaction.valid?
end
end

View File

@ -0,0 +1,62 @@
require 'test_helper'
class WalletServiceTest < ActiveSupport::TestCase
setup do
@admin = User.find_by(username: 'admin')
@jdupond = User.find_by(username: 'jdupond')
@jdupond_wallet = @jdupond.wallet
@vlonchamp = User.find_by(username: 'vlonchamp')
@vlonchamp_wallet = @vlonchamp.wallet
end
test 'admin can credit a wallet' do
service = WalletService.new(user: @admin, wallet: @jdupond_wallet)
expected_amount = @jdupond_wallet.amount + 5
assert service.credit(5)
assert_equal @jdupond_wallet.amount, expected_amount
end
test 'create a credit transaction after credit amount to wallet' do
service = WalletService.new(user: @admin, wallet: @jdupond_wallet)
expected_amount = @jdupond_wallet.amount + 10
assert_equal 0, @jdupond_wallet.wallet_transactions.count
transaction = service.credit(10)
@jdupond_wallet.reload
assert transaction
assert_equal @jdupond_wallet.amount, expected_amount
assert_equal transaction.transaction_type, 'credit'
assert_equal transaction.amount, 10
assert_equal transaction.user, @admin
assert_equal transaction.wallet, @jdupond_wallet
end
test 'create a debit transaction after debit amount to wallet' do
service = WalletService.new(user: @vlonchamp, wallet: @vlonchamp_wallet)
expected_amount = @vlonchamp_wallet.amount - 5
transaction = service.debit(5, nil)
@vlonchamp_wallet.reload
assert transaction
assert_equal @vlonchamp_wallet.amount, expected_amount
assert_equal transaction.transaction_type, 'debit'
assert_equal transaction.amount, 5
assert_equal transaction.user, @vlonchamp
assert_equal transaction.wallet, @vlonchamp_wallet
end
test 'dont debit amount > wallet amount' do
service = WalletService.new(user: @vlonchamp, wallet: @vlonchamp_wallet)
expected_amount = @vlonchamp_wallet.amount
service.debit(100, nil)
@vlonchamp_wallet.reload
assert_equal @vlonchamp_wallet.amount, expected_amount
end
test 'rollback debited amount if has an error when create wallet transaction' do
service = WalletService.new(wallet: @vlonchamp_wallet)
expected_amount = @vlonchamp_wallet.amount
transaction = service.debit(5, nil)
@vlonchamp_wallet.reload
assert_equal @vlonchamp_wallet.amount, expected_amount
assert_not transaction
end
end

View File

@ -0,0 +1,1063 @@
---
http_interactions:
- request:
method: post
uri: https://api.stripe.com/v1/tokens
body:
encoding: UTF-8
string: card[number]=4242424242424242&card[exp_month]=4&card[exp_year]=2017&card[cvc]=314
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '81'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:02:58 GMT
Content-Type:
- application/json
Content-Length:
- '778'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8DigzZOUKbFLP8
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "tok_17xHFG2sOmf47Nz9pZ4CafpU",
"object": "token",
"card": {
"id": "card_17xHFG2sOmf47Nz95yErDQbL",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"cvc_check": "unchecked",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
},
"client_ip": "86.76.5.109",
"created": 1459951378,
"livemode": false,
"type": "card",
"used": false
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:02:58 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoiceitems
body:
encoding: UTF-8
string: customer=cus_8CzNtM08NVlSGN&amount=3200&currency=usd&description=FORM1%2B+imprimante+3D+April+11%2C+2016+14%3A00+-+03%3A00+PM
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '125'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:02:58 GMT
Content-Type:
- application/json
Content-Length:
- '469'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8DigTaKJ04PVMc
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_17xHFG2sOmf47Nz9hhIaJZtF",
"object": "invoiceitem",
"amount": 3200,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1459951378,
"description": "FORM1+ imprimante 3D April 11, 2016 14:00 - 03:00 PM",
"discountable": true,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1459951378,
"end": 1459951378
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:02:58 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoiceitems
body:
encoding: UTF-8
string: customer=cus_8CzNtM08NVlSGN&amount=-1000&currency=usd&description=Wallet+-1000
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '125'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:02:58 GMT
Content-Type:
- application/json
Content-Length:
- '469'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8DigTaKJ04PVMc
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_17xHFG2sOmf47N59hh8aJSt6",
"object": "invoiceitem",
"amount": -1000,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1459951378,
"description": "Wallet -1000",
"discountable": true,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1459951378,
"end": 1459951378
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:02:58 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:02:59 GMT
Content-Type:
- application/json
Content-Length:
- '3462'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Digc2V3aKSGrn
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "cus_8CzNtM08NVlSGN",
"object": "customer",
"account_balance": 0,
"created": 1459948888,
"currency": "usd",
"default_source": "card_17xGjJ2sOmf47Nz9UrQOP8Cl",
"delinquent": false,
"description": "Jean Dupond",
"discount": null,
"email": "jean.dupond@gmail.com",
"livemode": false,
"metadata": {},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_17xGjJ2sOmf47Nz9UrQOP8Cl",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8CzNtM08NVlSGN",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/customers/cus_8CzNtM08NVlSGN/sources"
},
"subscriptions": {
"object": "list",
"data": [
{
"id": "sub_8Di9gqPLwt5IIC",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": true,
"canceled_at": 1459949404,
"current_period_end": 1462541399,
"current_period_start": 1459949399,
"customer": "cus_8CzNtM08NVlSGN",
"discount": null,
"ended_at": null,
"metadata": {},
"plan": {
"id": "mensuel-standard-month-20160404171519",
"object": "plan",
"amount": 3000,
"created": 1459782921,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"name": "Mensuel - standard, association - month",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1459949399,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
},
{
"id": "sub_8Di2VadRvr7A99",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": true,
"canceled_at": 1459948972,
"current_period_end": 1462540968,
"current_period_start": 1459948968,
"customer": "cus_8CzNtM08NVlSGN",
"discount": null,
"ended_at": null,
"metadata": {},
"plan": {
"id": "mensuel-standard-month-20160404171519",
"object": "plan",
"amount": 3000,
"created": 1459782921,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"name": "Mensuel - standard, association - month",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1459948968,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
],
"has_more": false,
"total_count": 2,
"url": "/v1/customers/cus_8CzNtM08NVlSGN/subscriptions"
}
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:02:59 GMT
- request:
method: post
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/sources
body:
encoding: UTF-8
string: card=tok_17xHFG2sOmf47Nz9pZ4CafpU
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '33'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:03:00 GMT
Content-Type:
- application/json
Content-Length:
- '577'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8DigAxuQClwx3A
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "card_17xHFG2sOmf47Nz95yErDQbL",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8CzNtM08NVlSGN",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:03:00 GMT
- request:
method: post
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: UTF-8
string: default_source=card_17xHFG2sOmf47Nz95yErDQbL
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '44'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:03:01 GMT
Content-Type:
- application/json
Content-Length:
- '4190'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dig1Js3cBEeqQ
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "cus_8CzNtM08NVlSGN",
"object": "customer",
"account_balance": 0,
"created": 1459948888,
"currency": "usd",
"default_source": "card_17xHFG2sOmf47Nz95yErDQbL",
"delinquent": false,
"description": "Jean Dupond",
"discount": null,
"email": "jean.dupond@gmail.com",
"livemode": false,
"metadata": {},
"shipping": null,
"sources": {
"object": "list",
"data": [
{
"id": "card_17xHFG2sOmf47Nz95yErDQbL",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8CzNtM08NVlSGN",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
},
{
"id": "card_17xGjJ2sOmf47Nz9UrQOP8Cl",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"customer": "cus_8CzNtM08NVlSGN",
"cvc_check": "pass",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
}
],
"has_more": false,
"total_count": 2,
"url": "/v1/customers/cus_8CzNtM08NVlSGN/sources"
},
"subscriptions": {
"object": "list",
"data": [
{
"id": "sub_8Di9gqPLwt5IIC",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": true,
"canceled_at": 1459949404,
"current_period_end": 1462541399,
"current_period_start": 1459949399,
"customer": "cus_8CzNtM08NVlSGN",
"discount": null,
"ended_at": null,
"metadata": {},
"plan": {
"id": "mensuel-standard-month-20160404171519",
"object": "plan",
"amount": 3000,
"created": 1459782921,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"name": "Mensuel - standard, association - month",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1459949399,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
},
{
"id": "sub_8Di2VadRvr7A99",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": true,
"canceled_at": 1459948972,
"current_period_end": 1462540968,
"current_period_start": 1459948968,
"customer": "cus_8CzNtM08NVlSGN",
"discount": null,
"ended_at": null,
"metadata": {},
"plan": {
"id": "mensuel-standard-month-20160404171519",
"object": "plan",
"amount": 3000,
"created": 1459782921,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"name": "Mensuel - standard, association - month",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1459948968,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
],
"has_more": false,
"total_count": 2,
"url": "/v1/customers/cus_8CzNtM08NVlSGN/subscriptions"
}
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:03:01 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoices
body:
encoding: UTF-8
string: customer=cus_8CzNtM08NVlSGN
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '27'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:03:02 GMT
Content-Type:
- application/json
Content-Length:
- '1426'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8DigRXqOIStdA0
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "in_17xHFK2sOmf47Nz9jegPFlNt",
"object": "invoice",
"amount_due": 2200,
"application_fee": null,
"attempt_count": 0,
"attempted": false,
"charge": null,
"closed": false,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1459951382,
"description": null,
"discount": null,
"ending_balance": null,
"forgiven": false,
"lines": {
"object": "list",
"data": [
{
"id": "ii_17xHFG2sOmf47Nz9hhIaJZtF",
"object": "line_item",
"amount": 3200,
"currency": "usd",
"description": "FORM1+ imprimante 3D April 11, 2016 14:00 - 03:00 PM",
"discountable": true,
"livemode": false,
"metadata": {},
"period": {
"start": 1459951378,
"end": 1459951378
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null,
"type": "invoiceitem"
},
{
"id": "ii_17xHFG2sOmf47N59hh8aJSt6",
"object": "invoiceitem",
"amount": -1000,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1459951378,
"description": "Wallet -1000",
"discountable": true,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1459951378,
"end": 1459951378
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/invoices/in_17xHFK2sOmf47Nz9jegPFlNt/lines"
},
"livemode": false,
"metadata": {},
"next_payment_attempt": 1459954982,
"paid": false,
"period_end": 1459951382,
"period_start": 1459948968,
"receipt_number": null,
"starting_balance": 0,
"statement_descriptor": null,
"subscription": null,
"subtotal": 2200,
"tax": null,
"tax_percent": null,
"total": 2200,
"webhooks_delivered_at": null
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:03:02 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoices/in_17xHFK2sOmf47Nz9jegPFlNt/pay
body:
encoding: ASCII-8BIT
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
Content-Length:
- '0'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:03:03 GMT
Content-Type:
- application/json
Content-Length:
- '1445'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8DigckzVuj8MLI
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "in_17xHFK2sOmf47Nz9jegPFlNt",
"object": "invoice",
"amount_due": 2200,
"application_fee": null,
"attempt_count": 1,
"attempted": true,
"charge": "ch_17xHFL2sOmf47Nz9FCQ0BJKc",
"closed": true,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1459951382,
"description": null,
"discount": null,
"ending_balance": 0,
"forgiven": false,
"lines": {
"object": "list",
"data": [
{
"id": "ii_17xHFG2sOmf47Nz9hhIaJZtF",
"object": "line_item",
"amount": 3200,
"currency": "usd",
"description": "FORM1+ imprimante 3D April 11, 2016 14:00 - 03:00 PM",
"discountable": true,
"livemode": false,
"metadata": {},
"period": {
"start": 1459951378,
"end": 1459951378
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null,
"type": "invoiceitem"
},
{
"id": "ii_17xHFG2sOmf47N59hh8aJSt6",
"object": "invoiceitem",
"amount": -1000,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1459951378,
"description": "Wallet -1000",
"discountable": true,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1459951378,
"end": 1459951378
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
],
"has_more": false,
"total_count": 1,
"url": "/v1/invoices/in_17xHFK2sOmf47Nz9jegPFlNt/lines"
},
"livemode": false,
"metadata": {},
"next_payment_attempt": null,
"paid": true,
"period_end": 1459951382,
"period_start": 1459948968,
"receipt_number": null,
"starting_balance": 0,
"statement_descriptor": null,
"subscription": null,
"subtotal": 2200,
"tax": null,
"tax_percent": null,
"total": 2200,
"webhooks_delivered_at": 1459951382
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:03:03 GMT
- request:
method: delete
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/sources/card_17xHFG2sOmf47Nz95yErDQbL
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:03:04 GMT
Content-Type:
- application/json
Content-Length:
- '63'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dig3VHawFrxab
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"deleted": true,
"id": "card_17xHFG2sOmf47Nz95yErDQbL"
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:03:04 GMT
recorded_with: VCR 3.0.1

View File

@ -18,9 +18,9 @@ http_interactions:
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '81'
response:
@ -31,11 +31,11 @@ http_interactions:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:31:05 GMT
- Mon, 11 Jul 2016 13:26:13 GMT
Content-Type:
- application/json
Content-Length:
- '778'
- '780'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
@ -49,7 +49,7 @@ http_interactions:
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dj8hOci59D4xC
- req_8nflaXEiTf6O0X
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
@ -58,10 +58,10 @@ http_interactions:
encoding: UTF-8
string: |
{
"id": "tok_17xHgT2sOmf47Nz962TaLtD7",
"id": "tok_18W4QL2sOmf47Nz9GM695H9O",
"object": "token",
"card": {
"id": "card_17xHgT2sOmf47Nz98eSsgCfX",
"id": "card_18W4QL2sOmf47Nz9NuqbiJMr",
"object": "card",
"address_city": null,
"address_country": null,
@ -84,20 +84,20 @@ http_interactions:
"name": null,
"tokenization_method": null
},
"client_ip": "86.76.5.109",
"created": 1459953065,
"client_ip": "82.122.118.54",
"created": 1468243573,
"livemode": false,
"type": "card",
"used": false
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:31:05 GMT
recorded_at: Mon, 11 Jul 2016 13:26:13 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoiceitems
body:
encoding: UTF-8
string: customer=cus_8Di1wjdVktv5kt&amount=3200&currency=usd&description=FORM1%2B+imprimante+3D+April+11%2C+2016+14%3A00+-+03%3A00+PM
string: customer=cus_8Di1wjdVktv5kt&amount=3200&currency=usd&description=FORM1%2B+imprimante+3D+July+10%2C+2016+14%3A00+-+03%3A00+PM
headers:
Accept:
- "*/*; q=0.5, application/xml"
@ -110,11 +110,11 @@ http_interactions:
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '125'
- '124'
response:
status:
code: 200
@ -123,11 +123,11 @@ http_interactions:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:31:06 GMT
- Mon, 11 Jul 2016 13:26:14 GMT
Content-Type:
- application/json
Content-Length:
- '469'
- '468'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
@ -141,7 +141,7 @@ http_interactions:
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dj87wp0RJ3Z71
- req_8nflWbFKH0Wr7j
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
@ -150,20 +150,20 @@ http_interactions:
encoding: UTF-8
string: |
{
"id": "ii_17xHgU2sOmf47Nz9Pp3l4ZAA",
"id": "ii_18W4QM2sOmf47Nz9g7EdrbZV",
"object": "invoiceitem",
"amount": 3200,
"currency": "usd",
"customer": "cus_8Di1wjdVktv5kt",
"date": 1459953066,
"description": "FORM1+ imprimante 3D April 11, 2016 14:00 - 03:00 PM",
"date": 1468243574,
"description": "FORM1+ imprimante 3D July 10, 2016 14:00 - 03:00 PM",
"discountable": true,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1459953066,
"end": 1459953066
"start": 1468243574,
"end": 1468243574
},
"plan": null,
"proration": false,
@ -171,7 +171,7 @@ http_interactions:
"subscription": null
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:31:06 GMT
recorded_at: Mon, 11 Jul 2016 13:26:14 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8Di1wjdVktv5kt
@ -190,9 +190,9 @@ http_interactions:
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
@ -201,11 +201,11 @@ http_interactions:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:31:07 GMT
- Mon, 11 Jul 2016 13:26:15 GMT
Content-Type:
- application/json
Content-Length:
- '3462'
- '1408'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
@ -219,7 +219,7 @@ http_interactions:
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dj8aOsnrVp2zU
- req_8nflczxuJx3Fit
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
@ -233,7 +233,7 @@ http_interactions:
"account_balance": 0,
"created": 1459948888,
"currency": "usd",
"default_source": "card_17xGjJ2sOmf47Nz9UrQOP8Cl",
"default_source": "card_17z7CT2sOmf47Nz9wtWkhGor",
"delinquent": false,
"description": "Jean Dupond",
"discount": null,
@ -245,7 +245,7 @@ http_interactions:
"object": "list",
"data": [
{
"id": "card_17xGjJ2sOmf47Nz9UrQOP8Cl",
"id": "card_17z7CT2sOmf47Nz9wtWkhGor",
"object": "card",
"address_city": null,
"address_country": null,
@ -276,87 +276,20 @@ http_interactions:
},
"subscriptions": {
"object": "list",
"data": [
{
"id": "sub_8Di9gqPLwt5IIC",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": true,
"canceled_at": 1459949404,
"current_period_end": 1462541399,
"current_period_start": 1459949399,
"customer": "cus_8Di1wjdVktv5kt",
"discount": null,
"ended_at": null,
"metadata": {},
"plan": {
"id": "mensuel-standard-month-20160404171519",
"object": "plan",
"amount": 3000,
"created": 1459782921,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"name": "Mensuel - standard, association - month",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1459949399,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
},
{
"id": "sub_8Di2VadRvr7A99",
"object": "subscription",
"application_fee_percent": null,
"cancel_at_period_end": true,
"canceled_at": 1459948972,
"current_period_end": 1462540968,
"current_period_start": 1459948968,
"customer": "cus_8Di1wjdVktv5kt",
"discount": null,
"ended_at": null,
"metadata": {},
"plan": {
"id": "mensuel-standard-month-20160404171519",
"object": "plan",
"amount": 3000,
"created": 1459782921,
"currency": "usd",
"interval": "month",
"interval_count": 1,
"livemode": false,
"metadata": {},
"name": "Mensuel - standard, association - month",
"statement_descriptor": null,
"trial_period_days": null
},
"quantity": 1,
"start": 1459948968,
"status": "active",
"tax_percent": null,
"trial_end": null,
"trial_start": null
}
],
"data": [],
"has_more": false,
"total_count": 2,
"total_count": 0,
"url": "/v1/customers/cus_8Di1wjdVktv5kt/subscriptions"
}
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:31:07 GMT
recorded_at: Mon, 11 Jul 2016 13:26:15 GMT
- request:
method: post
uri: https://api.stripe.com/v1/customers/cus_8Di1wjdVktv5kt/sources
body:
encoding: UTF-8
string: card=tok_17xHgT2sOmf47Nz962TaLtD7
string: card=tok_18W4QL2sOmf47Nz9GM695H9O
headers:
Accept:
- "*/*; q=0.5, application/xml"
@ -369,9 +302,9 @@ http_interactions:
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '33'
response:
@ -382,7 +315,7 @@ http_interactions:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:31:09 GMT
- Mon, 11 Jul 2016 13:26:16 GMT
Content-Type:
- application/json
Content-Length:
@ -400,7 +333,7 @@ http_interactions:
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dj8Q0yiZoox2F
- req_8nflIAexuhWlA2
Stripe-Version:
- '2015-10-16'
body:
@ -415,10 +348,10 @@ http_interactions:
}
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:31:09 GMT
recorded_at: Mon, 11 Jul 2016 13:26:16 GMT
- request:
method: delete
uri: https://api.stripe.com/v1/invoiceitems/ii_17xHgU2sOmf47Nz9Pp3l4ZAA
uri: https://api.stripe.com/v1/invoiceitems/ii_18W4QM2sOmf47Nz9g7EdrbZV
body:
encoding: US-ASCII
string: ''
@ -434,9 +367,9 @@ http_interactions:
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin14","engine":"ruby","publisher":"stripe","uname":"Darwin
MBP-sleede-Nicolas.local 14.5.0 Darwin Kernel Version 14.5.0: Wed Jul 29 02:26:53
PDT 2015; root:xnu-2782.40.9~1/RELEASE_X86_64 x86_64","hostname":"MBP-sleede-Nicolas.local"}'
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
@ -445,7 +378,7 @@ http_interactions:
Server:
- nginx
Date:
- Wed, 06 Apr 2016 14:31:09 GMT
- Mon, 11 Jul 2016 13:26:17 GMT
Content-Type:
- application/json
Content-Length:
@ -463,7 +396,7 @@ http_interactions:
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8Dj86hW0UVRjBL
- req_8nflVBopesOpHn
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
@ -473,8 +406,8 @@ http_interactions:
string: |
{
"deleted": true,
"id": "ii_17xHgU2sOmf47Nz9Pp3l4ZAA"
"id": "ii_18W4QM2sOmf47Nz9g7EdrbZV"
}
http_version:
recorded_at: Wed, 06 Apr 2016 14:31:09 GMT
recorded_at: Mon, 11 Jul 2016 13:26:17 GMT
recorded_with: VCR 3.0.1

View File

@ -0,0 +1,1149 @@
---
http_interactions:
- request:
method: post
uri: https://api.stripe.com/v1/tokens
body:
encoding: UTF-8
string: card[number]=4242424242424242&card[exp_month]=4&card[exp_year]=2017&card[cvc]=314
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '81'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:41 GMT
Content-Type:
- application/json
Content-Length:
- '778'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLLl2gl7snRL
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "tok_18ZhUf2sOmf47Nz96Yt86HJI",
"object": "token",
"card": {
"id": "card_18ZhUf2sOmf47Nz9LhkQeEmO",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"cvc_check": "unchecked",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
},
"client_ip": "90.52.50.40",
"created": 1469108741,
"livemode": false,
"type": "card",
"used": false
}
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:41 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoiceitems
body:
encoding: UTF-8
string: customer=cus_8CzNtM08NVlSGN&amount=0&currency=usd&description=Formation+Imprimante+3D+July+18%2C+2016+08%3A00+-+12%3A00+PM
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '122'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:42 GMT
Content-Type:
- application/json
Content-Length:
- '468'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLLf16BTkRiQ
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_18ZhUg2sOmf47Nz9vSsl5J9z",
"object": "invoiceitem",
"amount": 0,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1469108742,
"description": "Formation Imprimante 3D July 18, 2016 08:00 - 12:00 PM",
"discountable": true,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1469108742,
"end": 1469108742
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:42 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoiceitems
body:
encoding: UTF-8
string: customer=cus_8CzNtM08NVlSGN&amount=-1000&currency=usd&description=wallet+-10.0
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '78'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:43 GMT
Content-Type:
- application/json
Content-Length:
- '431'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLqGKwXBxt3a
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_18ZhUh2sOmf47Nz902ykGybB",
"object": "invoiceitem",
"amount": -1000,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1469108743,
"description": "wallet -10.0",
"discountable": false,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1469108743,
"end": 1469108743
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:43 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:44 GMT
Content-Type:
- application/json
Content-Length:
- '2561'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLPVnSOwscpK
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJjdXNfOEN6TnRNMDhOVmxTR04iLAogICJvYmplY3QiOiAi
Y3VzdG9tZXIiLAogICJhY2NvdW50X2JhbGFuY2UiOiAwLAogICJjcmVhdGVk
IjogMTQ1OTc4Mjg0OSwKICAiY3VycmVuY3kiOiAidXNkIiwKICAiZGVmYXVs
dF9zb3VyY2UiOiAiY2FyZF8xOFc0R0syc09tZjQ3Tno5SzZkZlNtWmwiLAog
ICJkZWxpbnF1ZW50IjogZmFsc2UsCiAgImRlc2NyaXB0aW9uIjogIlZhbmVz
c2EgTG9uY2hhbXAiLAogICJkaXNjb3VudCI6IG51bGwsCiAgImVtYWlsIjog
InZhbmVzc2EubG9uY2hhbXBAc2ZyLmZyIiwKICAibGl2ZW1vZGUiOiBmYWxz
ZSwKICAibWV0YWRhdGEiOiB7fSwKICAic2hpcHBpbmciOiBudWxsLAogICJz
b3VyY2VzIjogewogICAgIm9iamVjdCI6ICJsaXN0IiwKICAgICJkYXRhIjog
WwogICAgICB7CiAgICAgICAgImlkIjogImNhcmRfMThXNEdLMnNPbWY0N056
OUs2ZGZTbVpsIiwKICAgICAgICAib2JqZWN0IjogImNhcmQiLAogICAgICAg
ICJhZGRyZXNzX2NpdHkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2NvdW50
cnkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2xpbmUxIjogbnVsbCwKICAg
ICAgICAiYWRkcmVzc19saW5lMV9jaGVjayI6IG51bGwsCiAgICAgICAgImFk
ZHJlc3NfbGluZTIiOiBudWxsLAogICAgICAgICJhZGRyZXNzX3N0YXRlIjog
bnVsbCwKICAgICAgICAiYWRkcmVzc196aXAiOiBudWxsLAogICAgICAgICJh
ZGRyZXNzX3ppcF9jaGVjayI6IG51bGwsCiAgICAgICAgImJyYW5kIjogIlZp
c2EiLAogICAgICAgICJjb3VudHJ5IjogIlVTIiwKICAgICAgICAiY3VzdG9t
ZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAgICAgICAiY3ZjX2NoZWNr
IjogInBhc3MiLAogICAgICAgICJkeW5hbWljX2xhc3Q0IjogbnVsbCwKICAg
ICAgICAiZXhwX21vbnRoIjogNCwKICAgICAgICAiZXhwX3llYXIiOiAyMDE3
LAogICAgICAgICJmaW5nZXJwcmludCI6ICJvNTJqeWJSN2JubU5uNkFUIiwK
ICAgICAgICAiZnVuZGluZyI6ICJjcmVkaXQiLAogICAgICAgICJsYXN0NCI6
ICI0MjQyIiwKICAgICAgICAibWV0YWRhdGEiOiB7fSwKICAgICAgICAibmFt
ZSI6IG51bGwsCiAgICAgICAgInRva2VuaXphdGlvbl9tZXRob2QiOiBudWxs
CiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICJ0
b3RhbF9jb3VudCI6IDEsCiAgICAidXJsIjogIi92MS9jdXN0b21lcnMvY3Vz
XzhDek50TTA4TlZsU0dOL3NvdXJjZXMiCiAgfSwKICAic3Vic2NyaXB0aW9u
cyI6IHsKICAgICJvYmplY3QiOiAibGlzdCIsCiAgICAiZGF0YSI6IFsKICAg
ICAgewogICAgICAgICJpZCI6ICJzdWJfOG5mYlRHR0lRUlF6eDEiLAogICAg
ICAgICJvYmplY3QiOiAic3Vic2NyaXB0aW9uIiwKICAgICAgICAiYXBwbGlj
YXRpb25fZmVlX3BlcmNlbnQiOiBudWxsLAogICAgICAgICJjYW5jZWxfYXRf
cGVyaW9kX2VuZCI6IHRydWUsCiAgICAgICAgImNhbmNlbGVkX2F0IjogMTQ2
ODI0Mjk2MCwKICAgICAgICAiY3JlYXRlZCI6IDE0NjgyNDI5NTYsCiAgICAg
ICAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE0NzA5MjEzNTYsCiAgICAgICAg
ImN1cnJlbnRfcGVyaW9kX3N0YXJ0IjogMTQ2ODI0Mjk1NiwKICAgICAgICAi
Y3VzdG9tZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAgICAgICAiZGlz
Y291bnQiOiBudWxsLAogICAgICAgICJlbmRlZF9hdCI6IG51bGwsCiAgICAg
ICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgIm1ldGFkYXRhIjoge30s
CiAgICAgICAgInBsYW4iOiB7CiAgICAgICAgICAiaWQiOiAibWVuc3VlbC10
YXJpZi1yZWR1aXQtc3R1ZGVudC1tb250aC0yMDE2MDQwNDE3MTgyNyIsCiAg
ICAgICAgICAib2JqZWN0IjogInBsYW4iLAogICAgICAgICAgImFtb3VudCI6
IDIwMDAsCiAgICAgICAgICAiY3JlYXRlZCI6IDE0NTk3ODMxMDgsCiAgICAg
ICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAgICAgICAgICJpbnRlcnZhbCI6
ICJtb250aCIsCiAgICAgICAgICAiaW50ZXJ2YWxfY291bnQiOiAxLAogICAg
ICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgICAibWV0YWRhdGEi
OiB7fSwKICAgICAgICAgICJuYW1lIjogIk1lbnN1ZWwgdGFyaWYgcsOpZHVp
dCAtIMOpdHVkaWFudCwgLSBkZSAyNSBhbnMsIGVuc2VpZ25hbnQsIGRlbWFu
ZGV1ciBkJ2VtcGxvaSAtIG1vbnRoIiwKICAgICAgICAgICJzdGF0ZW1lbnRf
ZGVzY3JpcHRvciI6IG51bGwsCiAgICAgICAgICAidHJpYWxfcGVyaW9kX2Rh
eXMiOiBudWxsCiAgICAgICAgfSwKICAgICAgICAicXVhbnRpdHkiOiAxLAog
ICAgICAgICJzdGFydCI6IDE0NjgyNDI5NTYsCiAgICAgICAgInN0YXR1cyI6
ICJhY3RpdmUiLAogICAgICAgICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgICAg
ICAgInRyaWFsX2VuZCI6IG51bGwsCiAgICAgICAgInRyaWFsX3N0YXJ0Ijog
bnVsbAogICAgICB9CiAgICBdLAogICAgImhhc19tb3JlIjogZmFsc2UsCiAg
ICAidG90YWxfY291bnQiOiAxLAogICAgInVybCI6ICIvdjEvY3VzdG9tZXJz
L2N1c184Q3pOdE0wOE5WbFNHTi9zdWJzY3JpcHRpb25zIgogIH0KfQo=
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:44 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:45 GMT
Content-Type:
- application/json
Content-Length:
- '2561'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLZ9w0ZwAlFB
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJjdXNfOEN6TnRNMDhOVmxTR04iLAogICJvYmplY3QiOiAi
Y3VzdG9tZXIiLAogICJhY2NvdW50X2JhbGFuY2UiOiAwLAogICJjcmVhdGVk
IjogMTQ1OTc4Mjg0OSwKICAiY3VycmVuY3kiOiAidXNkIiwKICAiZGVmYXVs
dF9zb3VyY2UiOiAiY2FyZF8xOFc0R0syc09tZjQ3Tno5SzZkZlNtWmwiLAog
ICJkZWxpbnF1ZW50IjogZmFsc2UsCiAgImRlc2NyaXB0aW9uIjogIlZhbmVz
c2EgTG9uY2hhbXAiLAogICJkaXNjb3VudCI6IG51bGwsCiAgImVtYWlsIjog
InZhbmVzc2EubG9uY2hhbXBAc2ZyLmZyIiwKICAibGl2ZW1vZGUiOiBmYWxz
ZSwKICAibWV0YWRhdGEiOiB7fSwKICAic2hpcHBpbmciOiBudWxsLAogICJz
b3VyY2VzIjogewogICAgIm9iamVjdCI6ICJsaXN0IiwKICAgICJkYXRhIjog
WwogICAgICB7CiAgICAgICAgImlkIjogImNhcmRfMThXNEdLMnNPbWY0N056
OUs2ZGZTbVpsIiwKICAgICAgICAib2JqZWN0IjogImNhcmQiLAogICAgICAg
ICJhZGRyZXNzX2NpdHkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2NvdW50
cnkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2xpbmUxIjogbnVsbCwKICAg
ICAgICAiYWRkcmVzc19saW5lMV9jaGVjayI6IG51bGwsCiAgICAgICAgImFk
ZHJlc3NfbGluZTIiOiBudWxsLAogICAgICAgICJhZGRyZXNzX3N0YXRlIjog
bnVsbCwKICAgICAgICAiYWRkcmVzc196aXAiOiBudWxsLAogICAgICAgICJh
ZGRyZXNzX3ppcF9jaGVjayI6IG51bGwsCiAgICAgICAgImJyYW5kIjogIlZp
c2EiLAogICAgICAgICJjb3VudHJ5IjogIlVTIiwKICAgICAgICAiY3VzdG9t
ZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAgICAgICAiY3ZjX2NoZWNr
IjogInBhc3MiLAogICAgICAgICJkeW5hbWljX2xhc3Q0IjogbnVsbCwKICAg
ICAgICAiZXhwX21vbnRoIjogNCwKICAgICAgICAiZXhwX3llYXIiOiAyMDE3
LAogICAgICAgICJmaW5nZXJwcmludCI6ICJvNTJqeWJSN2JubU5uNkFUIiwK
ICAgICAgICAiZnVuZGluZyI6ICJjcmVkaXQiLAogICAgICAgICJsYXN0NCI6
ICI0MjQyIiwKICAgICAgICAibWV0YWRhdGEiOiB7fSwKICAgICAgICAibmFt
ZSI6IG51bGwsCiAgICAgICAgInRva2VuaXphdGlvbl9tZXRob2QiOiBudWxs
CiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICJ0
b3RhbF9jb3VudCI6IDEsCiAgICAidXJsIjogIi92MS9jdXN0b21lcnMvY3Vz
XzhDek50TTA4TlZsU0dOL3NvdXJjZXMiCiAgfSwKICAic3Vic2NyaXB0aW9u
cyI6IHsKICAgICJvYmplY3QiOiAibGlzdCIsCiAgICAiZGF0YSI6IFsKICAg
ICAgewogICAgICAgICJpZCI6ICJzdWJfOG5mYlRHR0lRUlF6eDEiLAogICAg
ICAgICJvYmplY3QiOiAic3Vic2NyaXB0aW9uIiwKICAgICAgICAiYXBwbGlj
YXRpb25fZmVlX3BlcmNlbnQiOiBudWxsLAogICAgICAgICJjYW5jZWxfYXRf
cGVyaW9kX2VuZCI6IHRydWUsCiAgICAgICAgImNhbmNlbGVkX2F0IjogMTQ2
ODI0Mjk2MCwKICAgICAgICAiY3JlYXRlZCI6IDE0NjgyNDI5NTYsCiAgICAg
ICAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE0NzA5MjEzNTYsCiAgICAgICAg
ImN1cnJlbnRfcGVyaW9kX3N0YXJ0IjogMTQ2ODI0Mjk1NiwKICAgICAgICAi
Y3VzdG9tZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAgICAgICAiZGlz
Y291bnQiOiBudWxsLAogICAgICAgICJlbmRlZF9hdCI6IG51bGwsCiAgICAg
ICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgIm1ldGFkYXRhIjoge30s
CiAgICAgICAgInBsYW4iOiB7CiAgICAgICAgICAiaWQiOiAibWVuc3VlbC10
YXJpZi1yZWR1aXQtc3R1ZGVudC1tb250aC0yMDE2MDQwNDE3MTgyNyIsCiAg
ICAgICAgICAib2JqZWN0IjogInBsYW4iLAogICAgICAgICAgImFtb3VudCI6
IDIwMDAsCiAgICAgICAgICAiY3JlYXRlZCI6IDE0NTk3ODMxMDgsCiAgICAg
ICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAgICAgICAgICJpbnRlcnZhbCI6
ICJtb250aCIsCiAgICAgICAgICAiaW50ZXJ2YWxfY291bnQiOiAxLAogICAg
ICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgICAibWV0YWRhdGEi
OiB7fSwKICAgICAgICAgICJuYW1lIjogIk1lbnN1ZWwgdGFyaWYgcsOpZHVp
dCAtIMOpdHVkaWFudCwgLSBkZSAyNSBhbnMsIGVuc2VpZ25hbnQsIGRlbWFu
ZGV1ciBkJ2VtcGxvaSAtIG1vbnRoIiwKICAgICAgICAgICJzdGF0ZW1lbnRf
ZGVzY3JpcHRvciI6IG51bGwsCiAgICAgICAgICAidHJpYWxfcGVyaW9kX2Rh
eXMiOiBudWxsCiAgICAgICAgfSwKICAgICAgICAicXVhbnRpdHkiOiAxLAog
ICAgICAgICJzdGFydCI6IDE0NjgyNDI5NTYsCiAgICAgICAgInN0YXR1cyI6
ICJhY3RpdmUiLAogICAgICAgICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgICAg
ICAgInRyaWFsX2VuZCI6IG51bGwsCiAgICAgICAgInRyaWFsX3N0YXJ0Ijog
bnVsbAogICAgICB9CiAgICBdLAogICAgImhhc19tb3JlIjogZmFsc2UsCiAg
ICAidG90YWxfY291bnQiOiAxLAogICAgInVybCI6ICIvdjEvY3VzdG9tZXJz
L2N1c184Q3pOdE0wOE5WbFNHTi9zdWJzY3JpcHRpb25zIgogIH0KfQo=
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:45 GMT
- request:
method: post
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/subscriptions
body:
encoding: UTF-8
string: plan=mensuel-tarif-reduit-student-month-20160404171827&source=tok_18ZhUf2sOmf47Nz96Yt86HJI
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '90'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:46 GMT
Content-Type:
- application/json
Content-Length:
- '926'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQL1c3JVc0vk5
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJzdWJfOHJRTGtsVVVVUWU2NmsiLAogICJvYmplY3QiOiAi
c3Vic2NyaXB0aW9uIiwKICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBu
dWxsLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IGZhbHNlLAogICJjYW5j
ZWxlZF9hdCI6IG51bGwsCiAgImNyZWF0ZWQiOiAxNDY5MTA4NzQ1LAogICJj
dXJyZW50X3BlcmlvZF9lbmQiOiAxNDcxNzg3MTQ1LAogICJjdXJyZW50X3Bl
cmlvZF9zdGFydCI6IDE0NjkxMDg3NDUsCiAgImN1c3RvbWVyIjogImN1c184
Q3pOdE0wOE5WbFNHTiIsCiAgImRpc2NvdW50IjogbnVsbCwKICAiZW5kZWRf
YXQiOiBudWxsLAogICJsaXZlbW9kZSI6IGZhbHNlLAogICJtZXRhZGF0YSI6
IHt9LAogICJwbGFuIjogewogICAgImlkIjogIm1lbnN1ZWwtdGFyaWYtcmVk
dWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQxNzE4MjciLAogICAgIm9iamVj
dCI6ICJwbGFuIiwKICAgICJhbW91bnQiOiAyMDAwLAogICAgImNyZWF0ZWQi
OiAxNDU5NzgzMTA4LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiaW50
ZXJ2YWwiOiAibW9udGgiLAogICAgImludGVydmFsX2NvdW50IjogMSwKICAg
ICJsaXZlbW9kZSI6IGZhbHNlLAogICAgIm1ldGFkYXRhIjoge30sCiAgICAi
bmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1aXQgLSDDqXR1ZGlhbnQsIC0g
ZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1hbmRldXIgZCdlbXBsb2kgLSBt
b250aCIsCiAgICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAogICAg
InRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbAogIH0sCiAgInF1YW50aXR5Ijog
MSwKICAic3RhcnQiOiAxNDY5MTA4NzQ1LAogICJzdGF0dXMiOiAiYWN0aXZl
IiwKICAidGF4X3BlcmNlbnQiOiBudWxsLAogICJ0cmlhbF9lbmQiOiBudWxs
LAogICJ0cmlhbF9zdGFydCI6IG51bGwKfQo=
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:46 GMT
- request:
method: get
uri: https://api.stripe.com/v1/invoices?customer=cus_8CzNtM08NVlSGN&limit=1
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:47 GMT
Content-Type:
- application/json
Content-Length:
- '3439'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLSdX3E9CFcJ
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJvYmplY3QiOiAibGlzdCIsCiAgImRhdGEiOiBbCiAgICB7CiAgICAg
ICJpZCI6ICJpbl8xOFpoVWoyc09tZjQ3Tno5cjhMS0lCTksiLAogICAgICAi
b2JqZWN0IjogImludm9pY2UiLAogICAgICAiYW1vdW50X2R1ZSI6IDEwMDAs
CiAgICAgICJhcHBsaWNhdGlvbl9mZWUiOiBudWxsLAogICAgICAiYXR0ZW1w
dF9jb3VudCI6IDEsCiAgICAgICJhdHRlbXB0ZWQiOiB0cnVlLAogICAgICAi
Y2hhcmdlIjogImNoXzE4WmhVazJzT21mNDdOejl2VVpXbWFZdSIsCiAgICAg
ICJjbG9zZWQiOiB0cnVlLAogICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAg
ICAgImN1c3RvbWVyIjogImN1c184Q3pOdE0wOE5WbFNHTiIsCiAgICAgICJk
YXRlIjogMTQ2OTEwODc0NSwKICAgICAgImRlc2NyaXB0aW9uIjogbnVsbCwK
ICAgICAgImRpc2NvdW50IjogbnVsbCwKICAgICAgImVuZGluZ19iYWxhbmNl
IjogMCwKICAgICAgImZvcmdpdmVuIjogZmFsc2UsCiAgICAgICJsaW5lcyI6
IHsKICAgICAgICAib2JqZWN0IjogImxpc3QiLAogICAgICAgICJkYXRhIjog
WwogICAgICAgICAgewogICAgICAgICAgICAiaWQiOiAiaWlfMThaaFVoMnNP
bWY0N056OTAyeWtHeWJCIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJsaW5l
X2l0ZW0iLAogICAgICAgICAgICAiYW1vdW50IjogLTEwMDAsCiAgICAgICAg
ICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAiZGVzY3JpcHRp
b24iOiAid2FsbGV0IC0xMC4wIiwKICAgICAgICAgICAgImRpc2NvdW50YWJs
ZSI6IGZhbHNlLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAg
ICAgICAgICAgIm1ldGFkYXRhIjoge30sCiAgICAgICAgICAgICJwZXJpb2Qi
OiB7CiAgICAgICAgICAgICAgInN0YXJ0IjogMTQ2OTEwODc0MywKICAgICAg
ICAgICAgICAiZW5kIjogMTQ2OTEwODc0MwogICAgICAgICAgICB9LAogICAg
ICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAgICAgICJwcm9yYXRpb24i
OiBmYWxzZSwKICAgICAgICAgICAgInF1YW50aXR5IjogbnVsbCwKICAgICAg
ICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgICAgICJ0eXBl
IjogImludm9pY2VpdGVtIgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAg
ICAgICAgICAgImlkIjogImlpXzE4WmhVZzJzT21mNDdOejl2U3NsNUo5eiIs
CiAgICAgICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAg
ICAgImFtb3VudCI6IDAsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2Qi
LAogICAgICAgICAgICAiZGVzY3JpcHRpb24iOiAiRm9ybWF0aW9uIEltcHJp
bWFudGUgM0QgSnVseSAxOCwgMjAxNiAwODowMCAtIDEyOjAwIFBNIiwKICAg
ICAgICAgICAgImRpc2NvdW50YWJsZSI6IHRydWUsCiAgICAgICAgICAgICJs
aXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgICAibWV0YWRhdGEiOiB7fSwK
ICAgICAgICAgICAgInBlcmlvZCI6IHsKICAgICAgICAgICAgICAic3RhcnQi
OiAxNDY5MTA4NzQyLAogICAgICAgICAgICAgICJlbmQiOiAxNDY5MTA4NzQy
CiAgICAgICAgICAgIH0sCiAgICAgICAgICAgICJwbGFuIjogbnVsbCwKICAg
ICAgICAgICAgInByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICAgICAicXVh
bnRpdHkiOiBudWxsLAogICAgICAgICAgICAic3Vic2NyaXB0aW9uIjogbnVs
bCwKICAgICAgICAgICAgInR5cGUiOiAiaW52b2ljZWl0ZW0iCiAgICAgICAg
ICB9LAogICAgICAgICAgewogICAgICAgICAgICAiaWQiOiAic3ViXzhyUUxr
bFVVVVFlNjZrIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJsaW5lX2l0ZW0i
LAogICAgICAgICAgICAiYW1vdW50IjogMjAwMCwKICAgICAgICAgICAgImN1
cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAgICJkZXNjcmlwdGlvbiI6IG51
bGwsCiAgICAgICAgICAgICJkaXNjb3VudGFibGUiOiB0cnVlLAogICAgICAg
ICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgIm1ldGFkYXRh
Ijoge30sCiAgICAgICAgICAgICJwZXJpb2QiOiB7CiAgICAgICAgICAgICAg
InN0YXJ0IjogMTQ2OTEwODc0NSwKICAgICAgICAgICAgICAiZW5kIjogMTQ3
MTc4NzE0NQogICAgICAgICAgICB9LAogICAgICAgICAgICAicGxhbiI6IHsK
ICAgICAgICAgICAgICAiaWQiOiAibWVuc3VlbC10YXJpZi1yZWR1aXQtc3R1
ZGVudC1tb250aC0yMDE2MDQwNDE3MTgyNyIsCiAgICAgICAgICAgICAgIm9i
amVjdCI6ICJwbGFuIiwKICAgICAgICAgICAgICAiYW1vdW50IjogMjAwMCwK
ICAgICAgICAgICAgICAiY3JlYXRlZCI6IDE0NTk3ODMxMDgsCiAgICAgICAg
ICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAgICAgImludGVy
dmFsIjogIm1vbnRoIiwKICAgICAgICAgICAgICAiaW50ZXJ2YWxfY291bnQi
OiAxLAogICAgICAgICAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAg
ICAgICAgICJtZXRhZGF0YSI6IHt9LAogICAgICAgICAgICAgICJuYW1lIjog
Ik1lbnN1ZWwgdGFyaWYgcsOpZHVpdCAtIMOpdHVkaWFudCwgLSBkZSAyNSBh
bnMsIGVuc2VpZ25hbnQsIGRlbWFuZGV1ciBkJ2VtcGxvaSAtIG1vbnRoIiwK
ICAgICAgICAgICAgICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAog
ICAgICAgICAgICAgICJ0cmlhbF9wZXJpb2RfZGF5cyI6IG51bGwKICAgICAg
ICAgICAgfSwKICAgICAgICAgICAgInByb3JhdGlvbiI6IGZhbHNlLAogICAg
ICAgICAgICAicXVhbnRpdHkiOiAxLAogICAgICAgICAgICAic3Vic2NyaXB0
aW9uIjogbnVsbCwKICAgICAgICAgICAgInR5cGUiOiAic3Vic2NyaXB0aW9u
IgogICAgICAgICAgfQogICAgICAgIF0sCiAgICAgICAgImhhc19tb3JlIjog
ZmFsc2UsCiAgICAgICAgInRvdGFsX2NvdW50IjogMywKICAgICAgICAidXJs
IjogIi92MS9pbnZvaWNlcy9pbl8xOFpoVWoyc09tZjQ3Tno5cjhMS0lCTksv
bGluZXMiCiAgICAgIH0sCiAgICAgICJsaXZlbW9kZSI6IGZhbHNlLAogICAg
ICAibWV0YWRhdGEiOiB7fSwKICAgICAgIm5leHRfcGF5bWVudF9hdHRlbXB0
IjogbnVsbCwKICAgICAgInBhaWQiOiB0cnVlLAogICAgICAicGVyaW9kX2Vu
ZCI6IDE0NjkxMDg3NDUsCiAgICAgICJwZXJpb2Rfc3RhcnQiOiAxNDY4MjQy
OTU2LAogICAgICAicmVjZWlwdF9udW1iZXIiOiBudWxsLAogICAgICAic3Rh
cnRpbmdfYmFsYW5jZSI6IDAsCiAgICAgICJzdGF0ZW1lbnRfZGVzY3JpcHRv
ciI6IG51bGwsCiAgICAgICJzdWJzY3JpcHRpb24iOiAic3ViXzhyUUxrbFVV
VVFlNjZrIiwKICAgICAgInN1YnRvdGFsIjogMTAwMCwKICAgICAgInRheCI6
IG51bGwsCiAgICAgICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgICAgICJ0b3Rh
bCI6IDEwMDAsCiAgICAgICJ3ZWJob29rc19kZWxpdmVyZWRfYXQiOiAxNDY5
MTA4NzQ2CiAgICB9CiAgXSwKICAiaGFzX21vcmUiOiB0cnVlLAogICJ1cmwi
OiAiL3YxL2ludm9pY2VzIgp9Cg==
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:47 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:48 GMT
Content-Type:
- application/json
Content-Length:
- '3698'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLtUHnQxh6hr
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJjdXNfOEN6TnRNMDhOVmxTR04iLAogICJvYmplY3QiOiAi
Y3VzdG9tZXIiLAogICJhY2NvdW50X2JhbGFuY2UiOiAwLAogICJjcmVhdGVk
IjogMTQ1OTc4Mjg0OSwKICAiY3VycmVuY3kiOiAidXNkIiwKICAiZGVmYXVs
dF9zb3VyY2UiOiAiY2FyZF8xOFpoVWYyc09tZjQ3Tno5TGhrUWVFbU8iLAog
ICJkZWxpbnF1ZW50IjogZmFsc2UsCiAgImRlc2NyaXB0aW9uIjogIlZhbmVz
c2EgTG9uY2hhbXAiLAogICJkaXNjb3VudCI6IG51bGwsCiAgImVtYWlsIjog
InZhbmVzc2EubG9uY2hhbXBAc2ZyLmZyIiwKICAibGl2ZW1vZGUiOiBmYWxz
ZSwKICAibWV0YWRhdGEiOiB7fSwKICAic2hpcHBpbmciOiBudWxsLAogICJz
b3VyY2VzIjogewogICAgIm9iamVjdCI6ICJsaXN0IiwKICAgICJkYXRhIjog
WwogICAgICB7CiAgICAgICAgImlkIjogImNhcmRfMThaaFVmMnNPbWY0N056
OUxoa1FlRW1PIiwKICAgICAgICAib2JqZWN0IjogImNhcmQiLAogICAgICAg
ICJhZGRyZXNzX2NpdHkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2NvdW50
cnkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2xpbmUxIjogbnVsbCwKICAg
ICAgICAiYWRkcmVzc19saW5lMV9jaGVjayI6IG51bGwsCiAgICAgICAgImFk
ZHJlc3NfbGluZTIiOiBudWxsLAogICAgICAgICJhZGRyZXNzX3N0YXRlIjog
bnVsbCwKICAgICAgICAiYWRkcmVzc196aXAiOiBudWxsLAogICAgICAgICJh
ZGRyZXNzX3ppcF9jaGVjayI6IG51bGwsCiAgICAgICAgImJyYW5kIjogIlZp
c2EiLAogICAgICAgICJjb3VudHJ5IjogIlVTIiwKICAgICAgICAiY3VzdG9t
ZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAgICAgICAiY3ZjX2NoZWNr
IjogInBhc3MiLAogICAgICAgICJkeW5hbWljX2xhc3Q0IjogbnVsbCwKICAg
ICAgICAiZXhwX21vbnRoIjogNCwKICAgICAgICAiZXhwX3llYXIiOiAyMDE3
LAogICAgICAgICJmaW5nZXJwcmludCI6ICJvNTJqeWJSN2JubU5uNkFUIiwK
ICAgICAgICAiZnVuZGluZyI6ICJjcmVkaXQiLAogICAgICAgICJsYXN0NCI6
ICI0MjQyIiwKICAgICAgICAibWV0YWRhdGEiOiB7fSwKICAgICAgICAibmFt
ZSI6IG51bGwsCiAgICAgICAgInRva2VuaXphdGlvbl9tZXRob2QiOiBudWxs
CiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICJ0
b3RhbF9jb3VudCI6IDEsCiAgICAidXJsIjogIi92MS9jdXN0b21lcnMvY3Vz
XzhDek50TTA4TlZsU0dOL3NvdXJjZXMiCiAgfSwKICAic3Vic2NyaXB0aW9u
cyI6IHsKICAgICJvYmplY3QiOiAibGlzdCIsCiAgICAiZGF0YSI6IFsKICAg
ICAgewogICAgICAgICJpZCI6ICJzdWJfOHJRTGtsVVVVUWU2NmsiLAogICAg
ICAgICJvYmplY3QiOiAic3Vic2NyaXB0aW9uIiwKICAgICAgICAiYXBwbGlj
YXRpb25fZmVlX3BlcmNlbnQiOiBudWxsLAogICAgICAgICJjYW5jZWxfYXRf
cGVyaW9kX2VuZCI6IGZhbHNlLAogICAgICAgICJjYW5jZWxlZF9hdCI6IG51
bGwsCiAgICAgICAgImNyZWF0ZWQiOiAxNDY5MTA4NzQ1LAogICAgICAgICJj
dXJyZW50X3BlcmlvZF9lbmQiOiAxNDcxNzg3MTQ1LAogICAgICAgICJjdXJy
ZW50X3BlcmlvZF9zdGFydCI6IDE0NjkxMDg3NDUsCiAgICAgICAgImN1c3Rv
bWVyIjogImN1c184Q3pOdE0wOE5WbFNHTiIsCiAgICAgICAgImRpc2NvdW50
IjogbnVsbCwKICAgICAgICAiZW5kZWRfYXQiOiBudWxsLAogICAgICAgICJs
aXZlbW9kZSI6IGZhbHNlLAogICAgICAgICJtZXRhZGF0YSI6IHt9LAogICAg
ICAgICJwbGFuIjogewogICAgICAgICAgImlkIjogIm1lbnN1ZWwtdGFyaWYt
cmVkdWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQxNzE4MjciLAogICAgICAg
ICAgIm9iamVjdCI6ICJwbGFuIiwKICAgICAgICAgICJhbW91bnQiOiAyMDAw
LAogICAgICAgICAgImNyZWF0ZWQiOiAxNDU5NzgzMTA4LAogICAgICAgICAg
ImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAiaW50ZXJ2YWwiOiAibW9u
dGgiLAogICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAg
ICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgIm1ldGFkYXRhIjoge30s
CiAgICAgICAgICAibmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1aXQgLSDD
qXR1ZGlhbnQsIC0gZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1hbmRldXIg
ZCdlbXBsb2kgLSBtb250aCIsCiAgICAgICAgICAic3RhdGVtZW50X2Rlc2Ny
aXB0b3IiOiBudWxsLAogICAgICAgICAgInRyaWFsX3BlcmlvZF9kYXlzIjog
bnVsbAogICAgICAgIH0sCiAgICAgICAgInF1YW50aXR5IjogMSwKICAgICAg
ICAic3RhcnQiOiAxNDY5MTA4NzQ1LAogICAgICAgICJzdGF0dXMiOiAiYWN0
aXZlIiwKICAgICAgICAidGF4X3BlcmNlbnQiOiBudWxsLAogICAgICAgICJ0
cmlhbF9lbmQiOiBudWxsLAogICAgICAgICJ0cmlhbF9zdGFydCI6IG51bGwK
ICAgICAgfSwKICAgICAgewogICAgICAgICJpZCI6ICJzdWJfOG5mYlRHR0lR
UlF6eDEiLAogICAgICAgICJvYmplY3QiOiAic3Vic2NyaXB0aW9uIiwKICAg
ICAgICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBudWxsLAogICAgICAg
ICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IHRydWUsCiAgICAgICAgImNhbmNl
bGVkX2F0IjogMTQ2ODI0Mjk2MCwKICAgICAgICAiY3JlYXRlZCI6IDE0Njgy
NDI5NTYsCiAgICAgICAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE0NzA5MjEz
NTYsCiAgICAgICAgImN1cnJlbnRfcGVyaW9kX3N0YXJ0IjogMTQ2ODI0Mjk1
NiwKICAgICAgICAiY3VzdG9tZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwK
ICAgICAgICAiZGlzY291bnQiOiBudWxsLAogICAgICAgICJlbmRlZF9hdCI6
IG51bGwsCiAgICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAgIm1l
dGFkYXRhIjoge30sCiAgICAgICAgInBsYW4iOiB7CiAgICAgICAgICAiaWQi
OiAibWVuc3VlbC10YXJpZi1yZWR1aXQtc3R1ZGVudC1tb250aC0yMDE2MDQw
NDE3MTgyNyIsCiAgICAgICAgICAib2JqZWN0IjogInBsYW4iLAogICAgICAg
ICAgImFtb3VudCI6IDIwMDAsCiAgICAgICAgICAiY3JlYXRlZCI6IDE0NTk3
ODMxMDgsCiAgICAgICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAgICAgICAg
ICJpbnRlcnZhbCI6ICJtb250aCIsCiAgICAgICAgICAiaW50ZXJ2YWxfY291
bnQiOiAxLAogICAgICAgICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAgICAg
ICAibWV0YWRhdGEiOiB7fSwKICAgICAgICAgICJuYW1lIjogIk1lbnN1ZWwg
dGFyaWYgcsOpZHVpdCAtIMOpdHVkaWFudCwgLSBkZSAyNSBhbnMsIGVuc2Vp
Z25hbnQsIGRlbWFuZGV1ciBkJ2VtcGxvaSAtIG1vbnRoIiwKICAgICAgICAg
ICJzdGF0ZW1lbnRfZGVzY3JpcHRvciI6IG51bGwsCiAgICAgICAgICAidHJp
YWxfcGVyaW9kX2RheXMiOiBudWxsCiAgICAgICAgfSwKICAgICAgICAicXVh
bnRpdHkiOiAxLAogICAgICAgICJzdGFydCI6IDE0NjgyNDI5NTYsCiAgICAg
ICAgInN0YXR1cyI6ICJhY3RpdmUiLAogICAgICAgICJ0YXhfcGVyY2VudCI6
IG51bGwsCiAgICAgICAgInRyaWFsX2VuZCI6IG51bGwsCiAgICAgICAgInRy
aWFsX3N0YXJ0IjogbnVsbAogICAgICB9CiAgICBdLAogICAgImhhc19tb3Jl
IjogZmFsc2UsCiAgICAidG90YWxfY291bnQiOiAyLAogICAgInVybCI6ICIv
djEvY3VzdG9tZXJzL2N1c184Q3pOdE0wOE5WbFNHTi9zdWJzY3JpcHRpb25z
IgogIH0KfQo=
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:48 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/subscriptions/sub_8rQLklUUUQe66k
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:48 GMT
Content-Type:
- application/json
Content-Length:
- '926'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLxhq9Ba8DPf
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJzdWJfOHJRTGtsVVVVUWU2NmsiLAogICJvYmplY3QiOiAi
c3Vic2NyaXB0aW9uIiwKICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBu
dWxsLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IGZhbHNlLAogICJjYW5j
ZWxlZF9hdCI6IG51bGwsCiAgImNyZWF0ZWQiOiAxNDY5MTA4NzQ1LAogICJj
dXJyZW50X3BlcmlvZF9lbmQiOiAxNDcxNzg3MTQ1LAogICJjdXJyZW50X3Bl
cmlvZF9zdGFydCI6IDE0NjkxMDg3NDUsCiAgImN1c3RvbWVyIjogImN1c184
Q3pOdE0wOE5WbFNHTiIsCiAgImRpc2NvdW50IjogbnVsbCwKICAiZW5kZWRf
YXQiOiBudWxsLAogICJsaXZlbW9kZSI6IGZhbHNlLAogICJtZXRhZGF0YSI6
IHt9LAogICJwbGFuIjogewogICAgImlkIjogIm1lbnN1ZWwtdGFyaWYtcmVk
dWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQxNzE4MjciLAogICAgIm9iamVj
dCI6ICJwbGFuIiwKICAgICJhbW91bnQiOiAyMDAwLAogICAgImNyZWF0ZWQi
OiAxNDU5NzgzMTA4LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiaW50
ZXJ2YWwiOiAibW9udGgiLAogICAgImludGVydmFsX2NvdW50IjogMSwKICAg
ICJsaXZlbW9kZSI6IGZhbHNlLAogICAgIm1ldGFkYXRhIjoge30sCiAgICAi
bmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1aXQgLSDDqXR1ZGlhbnQsIC0g
ZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1hbmRldXIgZCdlbXBsb2kgLSBt
b250aCIsCiAgICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAogICAg
InRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbAogIH0sCiAgInF1YW50aXR5Ijog
MSwKICAic3RhcnQiOiAxNDY5MTA4NzQ1LAogICJzdGF0dXMiOiAiYWN0aXZl
IiwKICAidGF4X3BlcmNlbnQiOiBudWxsLAogICJ0cmlhbF9lbmQiOiBudWxs
LAogICJ0cmlhbF9zdGFydCI6IG51bGwKfQo=
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:49 GMT
- request:
method: delete
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/subscriptions/sub_8rQLklUUUQe66k?at_period_end=true
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:49 GMT
Content-Type:
- application/json
Content-Length:
- '931'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLffnLhxa9Y2
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJzdWJfOHJRTGtsVVVVUWU2NmsiLAogICJvYmplY3QiOiAi
c3Vic2NyaXB0aW9uIiwKICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBu
dWxsLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IHRydWUsCiAgImNhbmNl
bGVkX2F0IjogMTQ2OTEwODc0OSwKICAiY3JlYXRlZCI6IDE0NjkxMDg3NDUs
CiAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE0NzE3ODcxNDUsCiAgImN1cnJl
bnRfcGVyaW9kX3N0YXJ0IjogMTQ2OTEwODc0NSwKICAiY3VzdG9tZXIiOiAi
Y3VzXzhDek50TTA4TlZsU0dOIiwKICAiZGlzY291bnQiOiBudWxsLAogICJl
bmRlZF9hdCI6IG51bGwsCiAgImxpdmVtb2RlIjogZmFsc2UsCiAgIm1ldGFk
YXRhIjoge30sCiAgInBsYW4iOiB7CiAgICAiaWQiOiAibWVuc3VlbC10YXJp
Zi1yZWR1aXQtc3R1ZGVudC1tb250aC0yMDE2MDQwNDE3MTgyNyIsCiAgICAi
b2JqZWN0IjogInBsYW4iLAogICAgImFtb3VudCI6IDIwMDAsCiAgICAiY3Jl
YXRlZCI6IDE0NTk3ODMxMDgsCiAgICAiY3VycmVuY3kiOiAidXNkIiwKICAg
ICJpbnRlcnZhbCI6ICJtb250aCIsCiAgICAiaW50ZXJ2YWxfY291bnQiOiAx
LAogICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAibWV0YWRhdGEiOiB7fSwK
ICAgICJuYW1lIjogIk1lbnN1ZWwgdGFyaWYgcsOpZHVpdCAtIMOpdHVkaWFu
dCwgLSBkZSAyNSBhbnMsIGVuc2VpZ25hbnQsIGRlbWFuZGV1ciBkJ2VtcGxv
aSAtIG1vbnRoIiwKICAgICJzdGF0ZW1lbnRfZGVzY3JpcHRvciI6IG51bGws
CiAgICAidHJpYWxfcGVyaW9kX2RheXMiOiBudWxsCiAgfSwKICAicXVhbnRp
dHkiOiAxLAogICJzdGFydCI6IDE0NjkxMDg3NDUsCiAgInN0YXR1cyI6ICJh
Y3RpdmUiLAogICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgInRyaWFsX2VuZCI6
IG51bGwsCiAgInRyaWFsX3N0YXJ0IjogbnVsbAp9Cg==
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:50 GMT
- request:
method: get
uri: https://api.stripe.com/v1/invoiceitems/ii_18ZhUg2sOmf47Nz9vSsl5J9z
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:50 GMT
Content-Type:
- application/json
Content-Length:
- '493'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQL4mVlBuIk4d
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_18ZhUg2sOmf47Nz9vSsl5J9z",
"object": "invoiceitem",
"amount": 0,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1469108742,
"description": "Formation Imprimante 3D July 18, 2016 08:00 - 12:00 PM",
"discountable": true,
"invoice": "in_18ZhUj2sOmf47Nz9r8LKIBNK",
"livemode": false,
"metadata": {},
"period": {
"start": 1469108742,
"end": 1469108742
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:50 GMT
- request:
method: get
uri: https://api.stripe.com/v1/invoiceitems/ii_18ZhUg2sOmf47Nz9vSsl5J9z
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_mGokO9TGtrVxMOyK4yZiktBE
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.6.0 Darwin Kernel Version 15.6.0: Thu Jun 23 18:25:34
PDT 2016; root:xnu-3248.60.10~1/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Thu, 21 Jul 2016 13:45:51 GMT
Content-Type:
- application/json
Content-Length:
- '493'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8rQLaiuoNH33sw
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_18ZhUg2sOmf47Nz9vSsl5J9z",
"object": "invoiceitem",
"amount": 0,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1469108742,
"description": "Formation Imprimante 3D July 18, 2016 08:00 - 12:00 PM",
"discountable": true,
"invoice": "in_18ZhUj2sOmf47Nz9r8LKIBNK",
"livemode": false,
"metadata": {},
"period": {
"start": 1469108742,
"end": 1469108742
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Thu, 21 Jul 2016 13:45:51 GMT
recorded_with: VCR 3.0.1

View File

@ -0,0 +1,821 @@
---
http_interactions:
- request:
method: post
uri: https://api.stripe.com/v1/tokens
body:
encoding: UTF-8
string: card[number]=4242424242424242&card[exp_month]=4&card[exp_year]=2017&card[cvc]=314
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '81'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:52 GMT
Content-Type:
- application/json
Content-Length:
- '780'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbr26ZMi1nMx
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "tok_18W4GK2sOmf47Nz9I7fm3Y18",
"object": "token",
"card": {
"id": "card_18W4GK2sOmf47Nz9K6dfSmZl",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"cvc_check": "unchecked",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
},
"client_ip": "82.122.118.54",
"created": 1468242952,
"livemode": false,
"type": "card",
"used": false
}
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:52 GMT
- request:
method: get
uri: https://api.stripe.com/v1/tokens/tok_18W4GK2sOmf47Nz9I7fm3Y18
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:53 GMT
Content-Type:
- application/json
Content-Length:
- '780'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbbQfs4YR066
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "tok_18W4GK2sOmf47Nz9I7fm3Y18",
"object": "token",
"card": {
"id": "card_18W4GK2sOmf47Nz9K6dfSmZl",
"object": "card",
"address_city": null,
"address_country": null,
"address_line1": null,
"address_line1_check": null,
"address_line2": null,
"address_state": null,
"address_zip": null,
"address_zip_check": null,
"brand": "Visa",
"country": "US",
"cvc_check": "unchecked",
"dynamic_last4": null,
"exp_month": 4,
"exp_year": 2017,
"fingerprint": "o52jybR7bnmNn6AT",
"funding": "credit",
"last4": "4242",
"metadata": {},
"name": null,
"tokenization_method": null
},
"client_ip": "82.122.118.54",
"created": 1468242952,
"livemode": false,
"type": "card",
"used": false
}
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:53 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:54 GMT
Content-Type:
- application/json
Content-Length:
- '655'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfb0Ez5UgkL6i
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "cus_8CzNtM08NVlSGN",
"object": "customer",
"account_balance": 0,
"created": 1459782849,
"currency": null,
"default_source": null,
"delinquent": false,
"description": "Vanessa Lonchamp",
"discount": null,
"email": "vanessa.lonchamp@sfr.fr",
"livemode": false,
"metadata": {},
"shipping": null,
"sources": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8CzNtM08NVlSGN/sources"
},
"subscriptions": {
"object": "list",
"data": [],
"has_more": false,
"total_count": 0,
"url": "/v1/customers/cus_8CzNtM08NVlSGN/subscriptions"
}
}
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:54 GMT
- request:
method: post
uri: https://api.stripe.com/v1/invoiceitems
body:
encoding: UTF-8
string: customer=cus_8CzNtM08NVlSGN&amount=-1000&currency=usd&description=wallet+-10.0
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '78'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:55 GMT
Content-Type:
- application/json
Content-Length:
- '431'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbS1DU8keH5x
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: UTF-8
string: |
{
"id": "ii_18W4GN2sOmf47Nz9K1dTfTyA",
"object": "invoiceitem",
"amount": -1000,
"currency": "usd",
"customer": "cus_8CzNtM08NVlSGN",
"date": 1468242955,
"description": "wallet -10.0",
"discountable": false,
"invoice": null,
"livemode": false,
"metadata": {},
"period": {
"start": 1468242955,
"end": 1468242955
},
"plan": null,
"proration": false,
"quantity": null,
"subscription": null
}
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:55 GMT
- request:
method: post
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/subscriptions
body:
encoding: UTF-8
string: plan=mensuel-tarif-reduit-student-month-20160404171827&source=tok_18W4GK2sOmf47Nz9I7fm3Y18
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
Content-Length:
- '90'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:57 GMT
Content-Type:
- application/json
Content-Length:
- '926'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbYSDVSvjiep
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJzdWJfOG5mYlRHR0lRUlF6eDEiLAogICJvYmplY3QiOiAi
c3Vic2NyaXB0aW9uIiwKICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBu
dWxsLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IGZhbHNlLAogICJjYW5j
ZWxlZF9hdCI6IG51bGwsCiAgImNyZWF0ZWQiOiAxNDY4MjQyOTU2LAogICJj
dXJyZW50X3BlcmlvZF9lbmQiOiAxNDcwOTIxMzU2LAogICJjdXJyZW50X3Bl
cmlvZF9zdGFydCI6IDE0NjgyNDI5NTYsCiAgImN1c3RvbWVyIjogImN1c184
Q3pOdE0wOE5WbFNHTiIsCiAgImRpc2NvdW50IjogbnVsbCwKICAiZW5kZWRf
YXQiOiBudWxsLAogICJsaXZlbW9kZSI6IGZhbHNlLAogICJtZXRhZGF0YSI6
IHt9LAogICJwbGFuIjogewogICAgImlkIjogIm1lbnN1ZWwtdGFyaWYtcmVk
dWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQxNzE4MjciLAogICAgIm9iamVj
dCI6ICJwbGFuIiwKICAgICJhbW91bnQiOiAyMDAwLAogICAgImNyZWF0ZWQi
OiAxNDU5NzgzMTA4LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiaW50
ZXJ2YWwiOiAibW9udGgiLAogICAgImludGVydmFsX2NvdW50IjogMSwKICAg
ICJsaXZlbW9kZSI6IGZhbHNlLAogICAgIm1ldGFkYXRhIjoge30sCiAgICAi
bmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1aXQgLSDDqXR1ZGlhbnQsIC0g
ZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1hbmRldXIgZCdlbXBsb2kgLSBt
b250aCIsCiAgICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAogICAg
InRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbAogIH0sCiAgInF1YW50aXR5Ijog
MSwKICAic3RhcnQiOiAxNDY4MjQyOTU2LAogICJzdGF0dXMiOiAiYWN0aXZl
IiwKICAidGF4X3BlcmNlbnQiOiBudWxsLAogICJ0cmlhbF9lbmQiOiBudWxs
LAogICJ0cmlhbF9zdGFydCI6IG51bGwKfQo=
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:57 GMT
- request:
method: get
uri: https://api.stripe.com/v1/invoices?customer=cus_8CzNtM08NVlSGN&limit=1
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:58 GMT
Content-Type:
- application/json
Content-Length:
- '2835'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbi8eORMWkgD
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJvYmplY3QiOiAibGlzdCIsCiAgImRhdGEiOiBbCiAgICB7CiAgICAg
ICJpZCI6ICJpbl8xOFc0R08yc09tZjQ3Tno5b291RFEzaGUiLAogICAgICAi
b2JqZWN0IjogImludm9pY2UiLAogICAgICAiYW1vdW50X2R1ZSI6IDEwMDAs
CiAgICAgICJhcHBsaWNhdGlvbl9mZWUiOiBudWxsLAogICAgICAiYXR0ZW1w
dF9jb3VudCI6IDEsCiAgICAgICJhdHRlbXB0ZWQiOiB0cnVlLAogICAgICAi
Y2hhcmdlIjogImNoXzE4VzRHTzJzT21mNDdOejlnb1k2T3lEbCIsCiAgICAg
ICJjbG9zZWQiOiB0cnVlLAogICAgICAiY3VycmVuY3kiOiAidXNkIiwKICAg
ICAgImN1c3RvbWVyIjogImN1c184Q3pOdE0wOE5WbFNHTiIsCiAgICAgICJk
YXRlIjogMTQ2ODI0Mjk1NiwKICAgICAgImRlc2NyaXB0aW9uIjogbnVsbCwK
ICAgICAgImRpc2NvdW50IjogbnVsbCwKICAgICAgImVuZGluZ19iYWxhbmNl
IjogMCwKICAgICAgImZvcmdpdmVuIjogZmFsc2UsCiAgICAgICJsaW5lcyI6
IHsKICAgICAgICAib2JqZWN0IjogImxpc3QiLAogICAgICAgICJkYXRhIjog
WwogICAgICAgICAgewogICAgICAgICAgICAiaWQiOiAiaWlfMThXNEdOMnNP
bWY0N056OUsxZFRmVHlBIiwKICAgICAgICAgICAgIm9iamVjdCI6ICJsaW5l
X2l0ZW0iLAogICAgICAgICAgICAiYW1vdW50IjogLTEwMDAsCiAgICAgICAg
ICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICAgICAiZGVzY3JpcHRp
b24iOiAid2FsbGV0IC0xMC4wIiwKICAgICAgICAgICAgImRpc2NvdW50YWJs
ZSI6IGZhbHNlLAogICAgICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAg
ICAgICAgICAgIm1ldGFkYXRhIjoge30sCiAgICAgICAgICAgICJwZXJpb2Qi
OiB7CiAgICAgICAgICAgICAgInN0YXJ0IjogMTQ2ODI0Mjk1NSwKICAgICAg
ICAgICAgICAiZW5kIjogMTQ2ODI0Mjk1NQogICAgICAgICAgICB9LAogICAg
ICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAgICAgICJwcm9yYXRpb24i
OiBmYWxzZSwKICAgICAgICAgICAgInF1YW50aXR5IjogbnVsbCwKICAgICAg
ICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgICAgICJ0eXBl
IjogImludm9pY2VpdGVtIgogICAgICAgICAgfSwKICAgICAgICAgIHsKICAg
ICAgICAgICAgImlkIjogInN1Yl84bmZiVEdHSVFSUXp4MSIsCiAgICAgICAg
ICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAgICAgImFtb3Vu
dCI6IDIwMDAsCiAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAg
ICAgICAgICAiZGVzY3JpcHRpb24iOiBudWxsLAogICAgICAgICAgICAiZGlz
Y291bnRhYmxlIjogdHJ1ZSwKICAgICAgICAgICAgImxpdmVtb2RlIjogZmFs
c2UsCiAgICAgICAgICAgICJtZXRhZGF0YSI6IHt9LAogICAgICAgICAgICAi
cGVyaW9kIjogewogICAgICAgICAgICAgICJzdGFydCI6IDE0NjgyNDI5NTYs
CiAgICAgICAgICAgICAgImVuZCI6IDE0NzA5MjEzNTYKICAgICAgICAgICAg
fSwKICAgICAgICAgICAgInBsYW4iOiB7CiAgICAgICAgICAgICAgImlkIjog
Im1lbnN1ZWwtdGFyaWYtcmVkdWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQx
NzE4MjciLAogICAgICAgICAgICAgICJvYmplY3QiOiAicGxhbiIsCiAgICAg
ICAgICAgICAgImFtb3VudCI6IDIwMDAsCiAgICAgICAgICAgICAgImNyZWF0
ZWQiOiAxNDU5NzgzMTA4LAogICAgICAgICAgICAgICJjdXJyZW5jeSI6ICJ1
c2QiLAogICAgICAgICAgICAgICJpbnRlcnZhbCI6ICJtb250aCIsCiAgICAg
ICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAgICAgICAi
bGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAgICAgICAibWV0YWRhdGEiOiB7
fSwKICAgICAgICAgICAgICAibmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1
aXQgLSDDqXR1ZGlhbnQsIC0gZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1h
bmRldXIgZCdlbXBsb2kgLSBtb250aCIsCiAgICAgICAgICAgICAgInN0YXRl
bWVudF9kZXNjcmlwdG9yIjogbnVsbCwKICAgICAgICAgICAgICAidHJpYWxf
cGVyaW9kX2RheXMiOiBudWxsCiAgICAgICAgICAgIH0sCiAgICAgICAgICAg
ICJwcm9yYXRpb24iOiBmYWxzZSwKICAgICAgICAgICAgInF1YW50aXR5Ijog
MSwKICAgICAgICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAg
ICAgICJ0eXBlIjogInN1YnNjcmlwdGlvbiIKICAgICAgICAgIH0KICAgICAg
ICBdLAogICAgICAgICJoYXNfbW9yZSI6IGZhbHNlLAogICAgICAgICJ0b3Rh
bF9jb3VudCI6IDIsCiAgICAgICAgInVybCI6ICIvdjEvaW52b2ljZXMvaW5f
MThXNEdPMnNPbWY0N056OW9vdURRM2hlL2xpbmVzIgogICAgICB9LAogICAg
ICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgIm1ldGFkYXRhIjoge30sCiAg
ICAgICJuZXh0X3BheW1lbnRfYXR0ZW1wdCI6IG51bGwsCiAgICAgICJwYWlk
IjogdHJ1ZSwKICAgICAgInBlcmlvZF9lbmQiOiAxNDY4MjQyOTU2LAogICAg
ICAicGVyaW9kX3N0YXJ0IjogMTQ2ODI0Mjk1NiwKICAgICAgInJlY2VpcHRf
bnVtYmVyIjogbnVsbCwKICAgICAgInN0YXJ0aW5nX2JhbGFuY2UiOiAwLAog
ICAgICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAogICAgICAic3Vi
c2NyaXB0aW9uIjogInN1Yl84bmZiVEdHSVFSUXp4MSIsCiAgICAgICJzdWJ0
b3RhbCI6IDEwMDAsCiAgICAgICJ0YXgiOiBudWxsLAogICAgICAidGF4X3Bl
cmNlbnQiOiBudWxsLAogICAgICAidG90YWwiOiAxMDAwLAogICAgICAid2Vi
aG9va3NfZGVsaXZlcmVkX2F0IjogMTQ2ODI0Mjk1NgogICAgfQogIF0sCiAg
Imhhc19tb3JlIjogZmFsc2UsCiAgInVybCI6ICIvdjEvaW52b2ljZXMiCn0K
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:58 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:59 GMT
Content-Type:
- application/json
Content-Length:
- '2556'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbxXXi48kJ9H
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJjdXNfOEN6TnRNMDhOVmxTR04iLAogICJvYmplY3QiOiAi
Y3VzdG9tZXIiLAogICJhY2NvdW50X2JhbGFuY2UiOiAwLAogICJjcmVhdGVk
IjogMTQ1OTc4Mjg0OSwKICAiY3VycmVuY3kiOiAidXNkIiwKICAiZGVmYXVs
dF9zb3VyY2UiOiAiY2FyZF8xOFc0R0syc09tZjQ3Tno5SzZkZlNtWmwiLAog
ICJkZWxpbnF1ZW50IjogZmFsc2UsCiAgImRlc2NyaXB0aW9uIjogIlZhbmVz
c2EgTG9uY2hhbXAiLAogICJkaXNjb3VudCI6IG51bGwsCiAgImVtYWlsIjog
InZhbmVzc2EubG9uY2hhbXBAc2ZyLmZyIiwKICAibGl2ZW1vZGUiOiBmYWxz
ZSwKICAibWV0YWRhdGEiOiB7fSwKICAic2hpcHBpbmciOiBudWxsLAogICJz
b3VyY2VzIjogewogICAgIm9iamVjdCI6ICJsaXN0IiwKICAgICJkYXRhIjog
WwogICAgICB7CiAgICAgICAgImlkIjogImNhcmRfMThXNEdLMnNPbWY0N056
OUs2ZGZTbVpsIiwKICAgICAgICAib2JqZWN0IjogImNhcmQiLAogICAgICAg
ICJhZGRyZXNzX2NpdHkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2NvdW50
cnkiOiBudWxsLAogICAgICAgICJhZGRyZXNzX2xpbmUxIjogbnVsbCwKICAg
ICAgICAiYWRkcmVzc19saW5lMV9jaGVjayI6IG51bGwsCiAgICAgICAgImFk
ZHJlc3NfbGluZTIiOiBudWxsLAogICAgICAgICJhZGRyZXNzX3N0YXRlIjog
bnVsbCwKICAgICAgICAiYWRkcmVzc196aXAiOiBudWxsLAogICAgICAgICJh
ZGRyZXNzX3ppcF9jaGVjayI6IG51bGwsCiAgICAgICAgImJyYW5kIjogIlZp
c2EiLAogICAgICAgICJjb3VudHJ5IjogIlVTIiwKICAgICAgICAiY3VzdG9t
ZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAgICAgICAiY3ZjX2NoZWNr
IjogInBhc3MiLAogICAgICAgICJkeW5hbWljX2xhc3Q0IjogbnVsbCwKICAg
ICAgICAiZXhwX21vbnRoIjogNCwKICAgICAgICAiZXhwX3llYXIiOiAyMDE3
LAogICAgICAgICJmaW5nZXJwcmludCI6ICJvNTJqeWJSN2JubU5uNkFUIiwK
ICAgICAgICAiZnVuZGluZyI6ICJjcmVkaXQiLAogICAgICAgICJsYXN0NCI6
ICI0MjQyIiwKICAgICAgICAibWV0YWRhdGEiOiB7fSwKICAgICAgICAibmFt
ZSI6IG51bGwsCiAgICAgICAgInRva2VuaXphdGlvbl9tZXRob2QiOiBudWxs
CiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUiOiBmYWxzZSwKICAgICJ0
b3RhbF9jb3VudCI6IDEsCiAgICAidXJsIjogIi92MS9jdXN0b21lcnMvY3Vz
XzhDek50TTA4TlZsU0dOL3NvdXJjZXMiCiAgfSwKICAic3Vic2NyaXB0aW9u
cyI6IHsKICAgICJvYmplY3QiOiAibGlzdCIsCiAgICAiZGF0YSI6IFsKICAg
ICAgewogICAgICAgICJpZCI6ICJzdWJfOG5mYlRHR0lRUlF6eDEiLAogICAg
ICAgICJvYmplY3QiOiAic3Vic2NyaXB0aW9uIiwKICAgICAgICAiYXBwbGlj
YXRpb25fZmVlX3BlcmNlbnQiOiBudWxsLAogICAgICAgICJjYW5jZWxfYXRf
cGVyaW9kX2VuZCI6IGZhbHNlLAogICAgICAgICJjYW5jZWxlZF9hdCI6IG51
bGwsCiAgICAgICAgImNyZWF0ZWQiOiAxNDY4MjQyOTU2LAogICAgICAgICJj
dXJyZW50X3BlcmlvZF9lbmQiOiAxNDcwOTIxMzU2LAogICAgICAgICJjdXJy
ZW50X3BlcmlvZF9zdGFydCI6IDE0NjgyNDI5NTYsCiAgICAgICAgImN1c3Rv
bWVyIjogImN1c184Q3pOdE0wOE5WbFNHTiIsCiAgICAgICAgImRpc2NvdW50
IjogbnVsbCwKICAgICAgICAiZW5kZWRfYXQiOiBudWxsLAogICAgICAgICJs
aXZlbW9kZSI6IGZhbHNlLAogICAgICAgICJtZXRhZGF0YSI6IHt9LAogICAg
ICAgICJwbGFuIjogewogICAgICAgICAgImlkIjogIm1lbnN1ZWwtdGFyaWYt
cmVkdWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQxNzE4MjciLAogICAgICAg
ICAgIm9iamVjdCI6ICJwbGFuIiwKICAgICAgICAgICJhbW91bnQiOiAyMDAw
LAogICAgICAgICAgImNyZWF0ZWQiOiAxNDU5NzgzMTA4LAogICAgICAgICAg
ImN1cnJlbmN5IjogInVzZCIsCiAgICAgICAgICAiaW50ZXJ2YWwiOiAibW9u
dGgiLAogICAgICAgICAgImludGVydmFsX2NvdW50IjogMSwKICAgICAgICAg
ICJsaXZlbW9kZSI6IGZhbHNlLAogICAgICAgICAgIm1ldGFkYXRhIjoge30s
CiAgICAgICAgICAibmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1aXQgLSDD
qXR1ZGlhbnQsIC0gZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1hbmRldXIg
ZCdlbXBsb2kgLSBtb250aCIsCiAgICAgICAgICAic3RhdGVtZW50X2Rlc2Ny
aXB0b3IiOiBudWxsLAogICAgICAgICAgInRyaWFsX3BlcmlvZF9kYXlzIjog
bnVsbAogICAgICAgIH0sCiAgICAgICAgInF1YW50aXR5IjogMSwKICAgICAg
ICAic3RhcnQiOiAxNDY4MjQyOTU2LAogICAgICAgICJzdGF0dXMiOiAiYWN0
aXZlIiwKICAgICAgICAidGF4X3BlcmNlbnQiOiBudWxsLAogICAgICAgICJ0
cmlhbF9lbmQiOiBudWxsLAogICAgICAgICJ0cmlhbF9zdGFydCI6IG51bGwK
ICAgICAgfQogICAgXSwKICAgICJoYXNfbW9yZSI6IGZhbHNlLAogICAgInRv
dGFsX2NvdW50IjogMSwKICAgICJ1cmwiOiAiL3YxL2N1c3RvbWVycy9jdXNf
OEN6TnRNMDhOVmxTR04vc3Vic2NyaXB0aW9ucyIKICB9Cn0K
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:58 GMT
- request:
method: get
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/subscriptions/sub_8nfbTGGIQRQzx1
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:15:59 GMT
Content-Type:
- application/json
Content-Length:
- '926'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbwT9nBtTlrw
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJzdWJfOG5mYlRHR0lRUlF6eDEiLAogICJvYmplY3QiOiAi
c3Vic2NyaXB0aW9uIiwKICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBu
dWxsLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IGZhbHNlLAogICJjYW5j
ZWxlZF9hdCI6IG51bGwsCiAgImNyZWF0ZWQiOiAxNDY4MjQyOTU2LAogICJj
dXJyZW50X3BlcmlvZF9lbmQiOiAxNDcwOTIxMzU2LAogICJjdXJyZW50X3Bl
cmlvZF9zdGFydCI6IDE0NjgyNDI5NTYsCiAgImN1c3RvbWVyIjogImN1c184
Q3pOdE0wOE5WbFNHTiIsCiAgImRpc2NvdW50IjogbnVsbCwKICAiZW5kZWRf
YXQiOiBudWxsLAogICJsaXZlbW9kZSI6IGZhbHNlLAogICJtZXRhZGF0YSI6
IHt9LAogICJwbGFuIjogewogICAgImlkIjogIm1lbnN1ZWwtdGFyaWYtcmVk
dWl0LXN0dWRlbnQtbW9udGgtMjAxNjA0MDQxNzE4MjciLAogICAgIm9iamVj
dCI6ICJwbGFuIiwKICAgICJhbW91bnQiOiAyMDAwLAogICAgImNyZWF0ZWQi
OiAxNDU5NzgzMTA4LAogICAgImN1cnJlbmN5IjogInVzZCIsCiAgICAiaW50
ZXJ2YWwiOiAibW9udGgiLAogICAgImludGVydmFsX2NvdW50IjogMSwKICAg
ICJsaXZlbW9kZSI6IGZhbHNlLAogICAgIm1ldGFkYXRhIjoge30sCiAgICAi
bmFtZSI6ICJNZW5zdWVsIHRhcmlmIHLDqWR1aXQgLSDDqXR1ZGlhbnQsIC0g
ZGUgMjUgYW5zLCBlbnNlaWduYW50LCBkZW1hbmRldXIgZCdlbXBsb2kgLSBt
b250aCIsCiAgICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAogICAg
InRyaWFsX3BlcmlvZF9kYXlzIjogbnVsbAogIH0sCiAgInF1YW50aXR5Ijog
MSwKICAic3RhcnQiOiAxNDY4MjQyOTU2LAogICJzdGF0dXMiOiAiYWN0aXZl
IiwKICAidGF4X3BlcmNlbnQiOiBudWxsLAogICJ0cmlhbF9lbmQiOiBudWxs
LAogICJ0cmlhbF9zdGFydCI6IG51bGwKfQo=
http_version:
recorded_at: Mon, 11 Jul 2016 13:15:59 GMT
- request:
method: delete
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/subscriptions/sub_8nfbTGGIQRQzx1?at_period_end=true
body:
encoding: US-ASCII
string: ''
headers:
Accept:
- "*/*; q=0.5, application/xml"
Accept-Encoding:
- gzip, deflate
User-Agent:
- Stripe/v1 RubyBindings/1.30.2
Authorization:
- Bearer sk_test_testfaketestfaketestfake
Content-Type:
- application/x-www-form-urlencoded
X-Stripe-Client-User-Agent:
- '{"bindings_version":"1.30.2","lang":"ruby","lang_version":"2.3.0 p0 (2015-12-25)","platform":"x86_64-darwin15","engine":"ruby","publisher":"stripe","uname":"Darwin
mbp-sleede-peng.home 15.4.0 Darwin Kernel Version 15.4.0: Fri Feb 26 22:08:05
PST 2016; root:xnu-3248.40.184~3/RELEASE_X86_64 x86_64","hostname":"mbp-sleede-peng.home"}'
response:
status:
code: 200
message: OK
headers:
Server:
- nginx
Date:
- Mon, 11 Jul 2016 13:16:00 GMT
Content-Type:
- application/json
Content-Length:
- '931'
Connection:
- keep-alive
Access-Control-Allow-Credentials:
- 'true'
Access-Control-Allow-Methods:
- GET, POST, HEAD, OPTIONS, DELETE
Access-Control-Allow-Origin:
- "*"
Access-Control-Max-Age:
- '300'
Cache-Control:
- no-cache, no-store
Request-Id:
- req_8nfbwqRs1dLP5C
Stripe-Version:
- '2015-10-16'
Strict-Transport-Security:
- max-age=31556926; includeSubDomains
body:
encoding: ASCII-8BIT
string: !binary |-
ewogICJpZCI6ICJzdWJfOG5mYlRHR0lRUlF6eDEiLAogICJvYmplY3QiOiAi
c3Vic2NyaXB0aW9uIiwKICAiYXBwbGljYXRpb25fZmVlX3BlcmNlbnQiOiBu
dWxsLAogICJjYW5jZWxfYXRfcGVyaW9kX2VuZCI6IHRydWUsCiAgImNhbmNl
bGVkX2F0IjogMTQ2ODI0Mjk2MCwKICAiY3JlYXRlZCI6IDE0NjgyNDI5NTYs
CiAgImN1cnJlbnRfcGVyaW9kX2VuZCI6IDE0NzA5MjEzNTYsCiAgImN1cnJl
bnRfcGVyaW9kX3N0YXJ0IjogMTQ2ODI0Mjk1NiwKICAiY3VzdG9tZXIiOiAi
Y3VzXzhDek50TTA4TlZsU0dOIiwKICAiZGlzY291bnQiOiBudWxsLAogICJl
bmRlZF9hdCI6IG51bGwsCiAgImxpdmVtb2RlIjogZmFsc2UsCiAgIm1ldGFk
YXRhIjoge30sCiAgInBsYW4iOiB7CiAgICAiaWQiOiAibWVuc3VlbC10YXJp
Zi1yZWR1aXQtc3R1ZGVudC1tb250aC0yMDE2MDQwNDE3MTgyNyIsCiAgICAi
b2JqZWN0IjogInBsYW4iLAogICAgImFtb3VudCI6IDIwMDAsCiAgICAiY3Jl
YXRlZCI6IDE0NTk3ODMxMDgsCiAgICAiY3VycmVuY3kiOiAidXNkIiwKICAg
ICJpbnRlcnZhbCI6ICJtb250aCIsCiAgICAiaW50ZXJ2YWxfY291bnQiOiAx
LAogICAgImxpdmVtb2RlIjogZmFsc2UsCiAgICAibWV0YWRhdGEiOiB7fSwK
ICAgICJuYW1lIjogIk1lbnN1ZWwgdGFyaWYgcsOpZHVpdCAtIMOpdHVkaWFu
dCwgLSBkZSAyNSBhbnMsIGVuc2VpZ25hbnQsIGRlbWFuZGV1ciBkJ2VtcGxv
aSAtIG1vbnRoIiwKICAgICJzdGF0ZW1lbnRfZGVzY3JpcHRvciI6IG51bGws
CiAgICAidHJpYWxfcGVyaW9kX2RheXMiOiBudWxsCiAgfSwKICAicXVhbnRp
dHkiOiAxLAogICJzdGFydCI6IDE0NjgyNDI5NTYsCiAgInN0YXR1cyI6ICJh
Y3RpdmUiLAogICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgInRyaWFsX2VuZCI6
IG51bGwsCiAgInRyaWFsX3N0YXJ0IjogbnVsbAp9Cg==
http_version:
recorded_at: Mon, 11 Jul 2016 13:16:00 GMT
recorded_with: VCR 3.0.1