mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-17 06:52:27 +01:00
Merge branch 'cash' into dev
This commit is contained in:
commit
aa7748f8eb
@ -1 +1 @@
|
||||
2.4.4
|
||||
2.4.5-dev
|
||||
|
@ -1,5 +1,9 @@
|
||||
# Changelog Fab Manager
|
||||
|
||||
## next release
|
||||
- Ability to create coupons with cash amounts (previously only percentages were allowed)
|
||||
- Fix a bug: misconfigured Twitter's ENV variables results in HTTP error 500
|
||||
|
||||
## v2.4.4 2016 November 24
|
||||
|
||||
- Fix a bug: unable to rollback migration 20160906145713
|
||||
|
@ -227,6 +227,7 @@ See https://help.disqus.com/customer/portal/articles/466208-what-s-a-shortname-
|
||||
TWITTER_NAME
|
||||
|
||||
Identifier of the Twitter account, from witch the last tweet will be fetched and displayed on the home page.
|
||||
This value can be graphically overridden during the application's lifecycle in Admin/Customization/Home page/Twitter Feed.
|
||||
It will also be used for [Twitter Card analytics](https://dev.twitter.com/cards/analytics).
|
||||
|
||||
TWITTER_CONSUMER_KEY, TWITTER_CONSUMER_SECRET, TWITTER_ACCESS_TOKEN & TWITTER_ACCESS_TOKEN_SECRET
|
||||
|
@ -8,12 +8,13 @@ userValidities = ['once', 'forever']
|
||||
##
|
||||
# Controller used in the coupon creation page
|
||||
##
|
||||
Application.Controllers.controller "NewCouponController", ["$scope", "$state",'Coupon', 'growl', '_t'
|
||||
Application.Controllers.controller "NewCouponController", ["$scope", "$state", 'Coupon', 'growl', '_t'
|
||||
, ($scope, $state, Coupon, growl, _t) ->
|
||||
|
||||
## Values for the coupon currently created
|
||||
$scope.coupon =
|
||||
active: true
|
||||
type: 'percent_off'
|
||||
|
||||
## Options for the validity per user
|
||||
$scope.validities = userValidities
|
||||
@ -57,7 +58,7 @@ Application.Controllers.controller "NewCouponController", ["$scope", "$state",'C
|
||||
##
|
||||
# Controller used in the coupon edition page
|
||||
##
|
||||
Application.Controllers.controller "EditCouponController", ["$scope", "$state", 'Coupon', 'couponPromise', '_t'
|
||||
Application.Controllers.controller "EditCouponController", ["$scope", "$state", 'Coupon', 'couponPromise', '_t'
|
||||
, ($scope, $state, Coupon, couponPromise, _t) ->
|
||||
|
||||
### PUBLIC SCOPE ###
|
||||
|
@ -382,8 +382,8 @@ Application.Controllers.controller "ShowEventReservationsController", ["$scope",
|
||||
##
|
||||
# Controller used in the event creation page
|
||||
##
|
||||
Application.Controllers.controller "NewEventController", ["$scope", "$state", "$locale", 'CSRF', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t'
|
||||
, ($scope, $state, $locale, CSRF, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) ->
|
||||
Application.Controllers.controller "NewEventController", ["$scope", "$state", 'CSRF', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise', '_t'
|
||||
, ($scope, $state, CSRF, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise, _t) ->
|
||||
CSRF.setMetaTags()
|
||||
|
||||
## API URL where the form will be posted
|
||||
@ -425,10 +425,6 @@ Application.Controllers.controller "NewEventController", ["$scope", "$state", "$
|
||||
{label: _t('every_year'), value: 'year'}
|
||||
]
|
||||
|
||||
## currency symbol for the current locale (cf. angular-i18n)
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
|
||||
|
||||
|
||||
## Using the EventsController
|
||||
new EventsController($scope, $state)
|
||||
]
|
||||
@ -438,8 +434,8 @@ Application.Controllers.controller "NewEventController", ["$scope", "$state", "$
|
||||
##
|
||||
# Controller used in the events edition page
|
||||
##
|
||||
Application.Controllers.controller "EditEventController", ["$scope", "$state", "$stateParams", "$locale", 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise'
|
||||
, ($scope, $state, $stateParams, $locale, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise) ->
|
||||
Application.Controllers.controller "EditEventController", ["$scope", "$state", "$stateParams", 'CSRF', 'eventPromise', 'categoriesPromise', 'themesPromise', 'ageRangesPromise', 'priceCategoriesPromise'
|
||||
, ($scope, $state, $stateParams, CSRF, eventPromise, categoriesPromise, themesPromise, ageRangesPromise, priceCategoriesPromise) ->
|
||||
|
||||
### PUBLIC SCOPE ###
|
||||
|
||||
@ -454,9 +450,6 @@ Application.Controllers.controller "EditEventController", ["$scope", "$state", "
|
||||
## Retrieve the event details, in case of error the user is redirected to the events listing
|
||||
$scope.event = eventPromise
|
||||
|
||||
## currency symbol for the current locale (cf. angular-i18n)
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
|
||||
|
||||
## List of categories for the events
|
||||
$scope.categories = categoriesPromise
|
||||
|
||||
|
@ -421,10 +421,7 @@ Application.Controllers.controller "EditMemberController", ["$scope", "$state",
|
||||
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
|
||||
controller: ['$scope', '$uibModalInstance', 'Wallet', ($scope, $uibModalInstance, Wallet) ->
|
||||
|
||||
##
|
||||
# Modal dialog validation callback
|
||||
|
@ -78,8 +78,8 @@ class PlanController
|
||||
##
|
||||
# Controller used in the plan creation form
|
||||
##
|
||||
Application.Controllers.controller 'NewPlanController', ['$scope', '$uibModal', 'groups', 'plans', 'machines', 'prices', 'partners', 'CSRF', '$state', 'growl', '_t', '$locale'
|
||||
, ($scope, $uibModal, groups, plans, machines, prices, partners, CSRF, $state, growl, _t, $locale) ->
|
||||
Application.Controllers.controller 'NewPlanController', ['$scope', '$uibModal', 'groups', 'plans', 'machines', 'prices', 'partners', 'CSRF', '$state', 'growl', '_t'
|
||||
, ($scope, $uibModal, groups, plans, machines, prices, partners, CSRF, $state, growl, _t) ->
|
||||
|
||||
|
||||
|
||||
@ -119,10 +119,6 @@ Application.Controllers.controller 'NewPlanController', ['$scope', '$uibModal',
|
||||
$scope.method = 'POST'
|
||||
|
||||
|
||||
## currency symbol for the current locale (cf. angular-i18n)
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Checks if the partner contact is a valid data. Used in the form validation process
|
||||
@ -187,8 +183,8 @@ Application.Controllers.controller 'NewPlanController', ['$scope', '$uibModal',
|
||||
##
|
||||
# Controller used in the plan edition form
|
||||
##
|
||||
Application.Controllers.controller 'EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'prices', 'partners', 'CSRF', '$state', '$stateParams', 'growl', '$filter', '_t', '$locale', 'Plan'
|
||||
, ($scope, groups, plans, planPromise, machines, prices, partners, CSRF, $state, $stateParams, growl, $filter, _t, $locale, Plan) ->
|
||||
Application.Controllers.controller 'EditPlanController', ['$scope', 'groups', 'plans', 'planPromise', 'machines', 'prices', 'partners', 'CSRF', '$state', '$stateParams', 'growl', '$filter', '_t', 'Plan'
|
||||
, ($scope, groups, plans, planPromise, machines, prices, partners, CSRF, $state, $stateParams, growl, $filter, _t, Plan) ->
|
||||
|
||||
|
||||
|
||||
@ -208,10 +204,6 @@ Application.Controllers.controller 'EditPlanController', ['$scope', 'groups', 'p
|
||||
$scope.method = 'PATCH'
|
||||
|
||||
|
||||
## currency symbol for the current locale (cf. angular-i18n)
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
|
||||
|
||||
|
||||
|
||||
##
|
||||
# If a parent plan was set ($scope.plan.parent), the prices will be copied from this parent plan into
|
||||
|
@ -3,8 +3,8 @@
|
||||
##
|
||||
# Controller used in the prices edition page
|
||||
##
|
||||
Application.Controllers.controller "EditPricingController", ["$scope", "$state", '$uibModal', 'TrainingsPricing', '$filter', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', '_t'
|
||||
, ($scope, $state, $uibModal, TrainingsPricing, $filter, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, _t) ->
|
||||
Application.Controllers.controller "EditPricingController", ["$scope", "$state", '$uibModal', '$filter', 'TrainingsPricing', 'Credit', 'Pricing', 'Plan', 'Coupon', 'plans', 'groups', 'growl', 'machinesPricesPromise', 'Price', 'dialogs', 'trainingsPricingsPromise', 'trainingsPromise', 'machineCreditsPromise', 'machinesPromise', 'trainingCreditsPromise', 'couponsPromise', '_t'
|
||||
, ($scope, $state, $uibModal, $filter, TrainingsPricing, Credit, Pricing, Plan, Coupon, plans, groups, growl, machinesPricesPromise, Price, dialogs, trainingsPricingsPromise, trainingsPromise, machineCreditsPromise, machinesPromise, trainingCreditsPromise, couponsPromise, _t) ->
|
||||
|
||||
### PUBLIC SCOPE ###
|
||||
## List of machines prices (not considering any plan)
|
||||
|
@ -1,7 +1,7 @@
|
||||
'use strict'
|
||||
|
||||
Application.Controllers.controller 'ApplicationController', ["$rootScope", "$scope", "$window", "Session", "AuthService", "Auth", "$uibModal", "$state", 'growl', 'Notification', '$interval', "Setting", '_t', 'Version'
|
||||
, ($rootScope, $scope, $window, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version) ->
|
||||
Application.Controllers.controller 'ApplicationController', ["$rootScope", "$scope", "$window", '$locale', "Session", "AuthService", "Auth", "$uibModal", "$state", 'growl', 'Notification', '$interval', "Setting", '_t', 'Version'
|
||||
, ($rootScope, $scope, $window, $locale, Session, AuthService, Auth, $uibModal, $state, growl, Notification, $interval, Setting, _t, Version) ->
|
||||
|
||||
|
||||
|
||||
@ -18,6 +18,10 @@ Application.Controllers.controller 'ApplicationController', ["$rootScope", "$sco
|
||||
$scope.version =
|
||||
version: ''
|
||||
|
||||
## currency symbol for the current locale (cf. angular-i18n)
|
||||
$rootScope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM;
|
||||
|
||||
|
||||
##
|
||||
# Set the current user to the provided value and initialize the session
|
||||
# @param user {Object} Rails/Devise user
|
||||
|
@ -154,6 +154,7 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
|
||||
tickets: {}
|
||||
toReserve: false
|
||||
amountTotal : 0
|
||||
totalNoCoupon: 0
|
||||
totalSeats: 0
|
||||
|
||||
## Discount coupon to apply to the basket, if any
|
||||
@ -400,6 +401,7 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
|
||||
r = mkReservation($scope.ctrl.member, $scope.reserve, $scope.event)
|
||||
Price.compute mkRequestParams(r, $scope.coupon.applied), (res) ->
|
||||
$scope.reserve.amountTotal = res.price
|
||||
$scope.reserve.totalNoCoupon = res.price_without_coupon
|
||||
else
|
||||
$scope.reserve.amountTotal = null
|
||||
|
||||
@ -560,9 +562,9 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
|
||||
member: $scope.ctrl.member
|
||||
coupon: ->
|
||||
$scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'growl', 'wallet', 'helpers', '$locale', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, growl, wallet, helpers, $locale, $filter, coupon) ->
|
||||
# user wallet amount
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'growl', 'wallet', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, growl, wallet, helpers, $filter, coupon) ->
|
||||
# User's wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
# Price
|
||||
@ -574,8 +576,7 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
|
||||
# Reservation
|
||||
$scope.reservation = reservation
|
||||
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
# Callback for the stripe payment authorization
|
||||
@ -616,9 +617,9 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
|
||||
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
|
||||
coupon: ->
|
||||
$scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', '$locale', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, $locale, helpers, $filter, coupon) ->
|
||||
# user wallet amount
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, helpers, $filter, coupon) ->
|
||||
# User's wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
# Price
|
||||
@ -630,8 +631,7 @@ Application.Controllers.controller "ShowEventController", ["$scope", "$state", "
|
||||
# Reservation
|
||||
$scope.reservation = reservation
|
||||
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
# Button label
|
||||
|
@ -315,6 +315,9 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
|
||||
## total amount of the bill to pay
|
||||
$scope.amountTotal = 0
|
||||
|
||||
## total amount of the elements in the cart, without considering any coupon
|
||||
$scope.totalNoCoupon = 0
|
||||
|
||||
## Discount coupon to apply to the basket, if any
|
||||
$scope.coupon =
|
||||
applied: null
|
||||
@ -661,6 +664,7 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
|
||||
r = mkReservation($scope.ctrl.member, $scope.eventsReserved, $scope.selectedPlan)
|
||||
Price.compute mkRequestParams(r, $scope.coupon.applied), (res) ->
|
||||
$scope.amountTotal = res.price
|
||||
$scope.totalNoCoupon = res.price_without_coupon
|
||||
setSlotsDetails(res.details)
|
||||
else
|
||||
# otherwise we alert, this error musn't occur when the current user is not admin
|
||||
@ -782,8 +786,8 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
|
||||
CustomAsset.get({name: 'cgv-file'}).$promise
|
||||
coupon: ->
|
||||
$scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'wallet', 'helpers', '$locale', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, wallet, helpers, $locale, $filter, coupon) ->
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'cgv', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, cgv, Auth, Reservation, wallet, helpers, $filter, coupon) ->
|
||||
# user wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
@ -796,9 +800,6 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
|
||||
# Reservation
|
||||
$scope.reservation = reservation
|
||||
|
||||
# Currency symbol or abreviation for the current locale
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
@ -842,8 +843,8 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
|
||||
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
|
||||
coupon: ->
|
||||
$scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', '$locale', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, helpers, $filter, $locale, coupon) ->
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'Auth', 'Reservation', 'wallet', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, reservation, price, Auth, Reservation, wallet, helpers, $filter, coupon) ->
|
||||
|
||||
# user wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
@ -857,9 +858,6 @@ Application.Controllers.controller "ReserveMachineController", ["$scope", "$stat
|
||||
# Reservation
|
||||
$scope.reservation = reservation
|
||||
|
||||
# Currency symbol or abreviation for the current locale
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
|
@ -177,11 +177,14 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
|
||||
updateCartPrice = ->
|
||||
# first we check that a user was selected
|
||||
if Object.keys($scope.ctrl.member).length > 0
|
||||
$scope.cart.total = $scope.selectedPlan.amount
|
||||
# apply the coupon if any
|
||||
if $scope.coupon.applied
|
||||
$scope.cart.total = $scope.selectedPlan.amount
|
||||
# apply the coupon if any
|
||||
if $scope.coupon.applied
|
||||
if $scope.coupon.applied.type == 'percent_off'
|
||||
discount = $scope.cart.total * $scope.coupon.applied.percent_off / 100
|
||||
$scope.cart.total -= discount
|
||||
else if $scope.coupon.applied.type == 'amount_off'
|
||||
discount = $scope.coupon.applied.amount_off
|
||||
$scope.cart.total -= discount
|
||||
else
|
||||
$scope.reserve.amountTotal = null
|
||||
|
||||
@ -200,9 +203,9 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
|
||||
wallet: ->
|
||||
Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise
|
||||
coupon: -> $scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'CustomAsset', 'wallet', 'helpers', '$locale', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, CustomAsset, wallet, helpers, $locale, $filter, coupon) ->
|
||||
# user wallet amount
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'CustomAsset', 'wallet', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, CustomAsset, wallet, helpers, $filter, coupon) ->
|
||||
# User's wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
# Final price to pay by the user
|
||||
@ -211,9 +214,6 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
|
||||
# The plan that the user is about to subscribe
|
||||
$scope.selectedPlan = selectedPlan
|
||||
|
||||
# Currency symbol or abreviation for the current locale
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
@ -266,8 +266,8 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
|
||||
wallet: ->
|
||||
Wallet.getWalletByUser({user_id: $scope.ctrl.member.id}).$promise
|
||||
coupon: -> $scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'wallet', 'helpers', '$locale', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, wallet, helpers, $locale, $filter, coupon) ->
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'selectedPlan', 'member', 'price', 'Subscription', 'wallet', 'helpers', '$filter', 'coupon',
|
||||
($scope, $uibModalInstance, $state, selectedPlan, member, price, Subscription, wallet, helpers, $filter, coupon) ->
|
||||
# user wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
@ -277,9 +277,6 @@ Application.Controllers.controller "PlansIndexController", ["$scope", "$rootScop
|
||||
# price to pay
|
||||
$scope.amount = helpers.getAmountToPay($scope.price, wallet.amount)
|
||||
|
||||
# Currency symbol or abreviation for the current locale
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
|
@ -217,10 +217,25 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
# Number of projects added to the page when the user clicks on 'load more projects'
|
||||
PROJECTS_PER_PAGE = 16
|
||||
|
||||
$scope.openlabAppId = Fablab.openlabAppId
|
||||
|
||||
|
||||
### PUBLIC SCOPE ###
|
||||
$scope.search = { q: ($location.$$search.q || ""), from: ($location.$$search.from || undefined), machine_id: (parseInt($location.$$search.machine_id) || undefined), component_id: (parseInt($location.$$search.component_id) || undefined), theme_id: (parseInt($location.$$search.theme_id) || undefined) }
|
||||
|
||||
## Fab-manager's instance ID in the openLab network
|
||||
$scope.openlabAppId = Fablab.openlabAppId
|
||||
|
||||
## Is openLab enabled on the instance?
|
||||
$scope.openlab =
|
||||
projectsActive: Fablab.openlabProjectsActive
|
||||
searchOverWholeNetwork: false
|
||||
|
||||
## default search parameters
|
||||
$scope.search =
|
||||
q: ($location.$$search.q || "")
|
||||
from: ($location.$$search.from || undefined)
|
||||
machine_id: (parseInt($location.$$search.machine_id) || undefined)
|
||||
component_id: (parseInt($location.$$search.component_id) || undefined)
|
||||
theme_id: (parseInt($location.$$search.theme_id) || undefined)
|
||||
|
||||
## list of projects to display
|
||||
$scope.projects = []
|
||||
@ -234,32 +249,14 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
## list of components / used for filtering
|
||||
$scope.components = componentsPromise
|
||||
|
||||
$scope.openlab = {}
|
||||
$scope.openlab.projectsActive = Fablab.openlabProjectsActive
|
||||
|
||||
if $location.$$search.whole_network is 'f'
|
||||
$scope.openlab.searchOverWholeNetwork = false
|
||||
else
|
||||
$scope.openlab.searchOverWholeNetwork = $scope.openlab.projectsActive || false
|
||||
|
||||
normalizeProjectsAttrs = (projects)->
|
||||
projects.map((project)->
|
||||
project.project_image = project.image_url
|
||||
return project
|
||||
)
|
||||
|
||||
$scope.searchOverWholeNetworkChanged = ->
|
||||
setTimeout ->
|
||||
$scope.resetFiltersAndTriggerSearch()
|
||||
, 150
|
||||
|
||||
loadMoreCallback = (projectsPromise)->
|
||||
$scope.projects = $scope.projects.concat(projectsPromise.projects)
|
||||
updateUrlParam('page', $scope.projectsPagination.currentPage)
|
||||
|
||||
loadMoreOpenlabCallback = (projectsPromise)->
|
||||
$scope.projects = $scope.projects.concat(normalizeProjectsAttrs(projectsPromise.projects))
|
||||
updateUrlParam('page', $scope.projectsPagination.currentPage)
|
||||
|
||||
$scope.loadMore = ->
|
||||
if $scope.openlab.searchOverWholeNetwork is true
|
||||
@ -268,6 +265,7 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
$scope.projectsPagination.loadMore(search: $scope.search)
|
||||
|
||||
|
||||
|
||||
$scope.resetFiltersAndTriggerSearch = ->
|
||||
$scope.search.q = ""
|
||||
$scope.search.from = undefined
|
||||
@ -277,6 +275,8 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
$scope.setUrlQueryParams($scope.search)
|
||||
$scope.triggerSearch()
|
||||
|
||||
|
||||
|
||||
$scope.triggerSearch = ->
|
||||
currentPage = parseInt($location.$$search.page) || 1
|
||||
if $scope.openlab.searchOverWholeNetwork is true
|
||||
@ -298,6 +298,8 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
$scope.projectsPagination.totalCount = projectsPromise.meta.total
|
||||
$scope.projects = projectsPromise.projects
|
||||
|
||||
|
||||
|
||||
##
|
||||
# Callback to switch the user's view to the detailled project page
|
||||
# @param project {{slug:string}} The project to display
|
||||
@ -309,6 +311,8 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
else
|
||||
$state.go('app.public.projects_show', {id: project.slug})
|
||||
|
||||
|
||||
|
||||
##
|
||||
# function to set all url query search parameters from search object
|
||||
##
|
||||
@ -320,6 +324,21 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
updateUrlParam('component_id', search.component_id)
|
||||
updateUrlParam('machine_id', search.machine_id)
|
||||
|
||||
|
||||
|
||||
### PRIVATE SCOPE ###
|
||||
|
||||
##
|
||||
# Kind of constructor: these actions will be realized first when the controller is loaded
|
||||
##
|
||||
initialize = ->
|
||||
if $location.$$search.whole_network is 'f'
|
||||
$scope.openlab.searchOverWholeNetwork = false
|
||||
else
|
||||
$scope.openlab.searchOverWholeNetwork = $scope.openlab.projectsActive || false
|
||||
$scope.triggerSearch()
|
||||
|
||||
|
||||
##
|
||||
# function to update url query param, little hack to turn off reloadOnSearch and re-enable it after setting the params
|
||||
# params example: 'q' , 'presse-purée'
|
||||
@ -330,9 +349,30 @@ Application.Controllers.controller "ProjectsController", ["$scope", "$state", 'P
|
||||
$timeout ->
|
||||
$state.current.reloadOnSearch = undefined
|
||||
|
||||
## initialization
|
||||
$scope.triggerSearch()
|
||||
|
||||
|
||||
loadMoreCallback = (projectsPromise)->
|
||||
$scope.projects = $scope.projects.concat(projectsPromise.projects)
|
||||
updateUrlParam('page', $scope.projectsPagination.currentPage)
|
||||
|
||||
|
||||
|
||||
loadMoreOpenlabCallback = (projectsPromise)->
|
||||
$scope.projects = $scope.projects.concat(normalizeProjectsAttrs(projectsPromise.projects))
|
||||
updateUrlParam('page', $scope.projectsPagination.currentPage)
|
||||
|
||||
|
||||
|
||||
normalizeProjectsAttrs = (projects)->
|
||||
projects.map((project)->
|
||||
project.project_image = project.image_url
|
||||
return project
|
||||
)
|
||||
|
||||
|
||||
|
||||
## !!! MUST BE CALLED AT THE END of the controller
|
||||
initialize()
|
||||
]
|
||||
|
||||
|
||||
|
@ -137,6 +137,12 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
$scope.coupon =
|
||||
applied: null
|
||||
|
||||
## Total price of the cart, that the user will pay
|
||||
$scope.amountTotal = 0
|
||||
|
||||
## Total amount of the elements in the cart, without considering any coupon
|
||||
$scope.totalNoCoupon = 0
|
||||
|
||||
## fullCalendar (v2) configuration
|
||||
$scope.calendarConfig = CalendarConfig
|
||||
minTime: moment.duration(moment(settingsPromise.booking_window_start).format('HH:mm:ss'))
|
||||
@ -353,6 +359,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
r = mkReservation($scope.ctrl.member, $scope.selectedTraining, $scope.selectedPlan)
|
||||
Price.compute mkRequestParams(r, $scope.coupon.applied), (res) ->
|
||||
$scope.amountTotal = res.price
|
||||
$scope.totalNoCoupon = res.price_without_coupon
|
||||
else
|
||||
$scope.amountTotal = null
|
||||
|
||||
@ -426,7 +433,6 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
if $scope.ctrl.member
|
||||
# reserve a training if this training will not be reserved and is not about to move and not is completed
|
||||
if !event.is_reserved && !$scope.slotToModify && !event.is_completed
|
||||
$scope.coupon.applied = null
|
||||
if event != $scope.selectedTraining
|
||||
$scope.selectedTraining = event
|
||||
$scope.selectedTraining.offered = false
|
||||
@ -533,9 +539,9 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
CustomAsset.get({name: 'cgv-file'}).$promise
|
||||
coupon: ->
|
||||
$scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'wallet', 'cgv', 'Auth', 'Reservation', '$locale', 'helpers', '$filter', 'coupon'
|
||||
($scope, $uibModalInstance, $state, reservation, price, wallet, cgv, Auth, Reservation, $locale, helpers, $filter, coupon) ->
|
||||
# user wallet amount
|
||||
controller: ['$scope', '$uibModalInstance', '$state', 'reservation', 'price', 'wallet', 'cgv', 'Auth', 'Reservation', 'helpers', '$filter', 'coupon'
|
||||
($scope, $uibModalInstance, $state, reservation, price, wallet, cgv, Auth, Reservation, helpers, $filter, coupon) ->
|
||||
# User's wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
# Price
|
||||
@ -547,8 +553,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
# Reservation
|
||||
$scope.reservation = reservation
|
||||
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
##
|
||||
@ -594,9 +599,9 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
Wallet.getWalletByUser({user_id: reservation.user_id}).$promise
|
||||
coupon: ->
|
||||
$scope.coupon.applied
|
||||
controller: ['$scope', '$uibModalInstance', '$state', '$filter', 'reservation', 'price', 'wallet', 'Auth', 'Reservation', '$locale', 'helpers', 'coupon'
|
||||
($scope, $uibModalInstance, $state, $filter, reservation, price, wallet, Auth, Reservation, $locale, helpers, coupon) ->
|
||||
# user wallet amount
|
||||
controller: ['$scope', '$uibModalInstance', '$state', '$filter', 'reservation', 'price', 'wallet', 'Auth', 'Reservation', 'helpers', 'coupon'
|
||||
($scope, $uibModalInstance, $state, $filter, reservation, price, wallet, Auth, Reservation, helpers, coupon) ->
|
||||
# User's wallet amount
|
||||
$scope.walletAmount = wallet.amount
|
||||
|
||||
# Price
|
||||
@ -608,8 +613,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
# Reservation
|
||||
$scope.reservation = reservation
|
||||
|
||||
$scope.currencySymbol = $locale.NUMBER_FORMATS.CURRENCY_SYM
|
||||
|
||||
# Used in wallet info template to interpolate some translations
|
||||
$scope.numberFilter = $filter('number')
|
||||
|
||||
# Button label
|
||||
@ -649,7 +653,7 @@ Application.Controllers.controller "ReserveTrainingController", ["$scope", "$sta
|
||||
# first we check that a user was selected
|
||||
if Object.keys($scope.ctrl.member).length > 0
|
||||
r = mkReservation($scope.ctrl.member, training) # reservation without any Plan -> we get the training price
|
||||
Price.compute mkRequestParams(r, $scope.coupon.applied), (res) ->
|
||||
Price.compute mkRequestParams(r), (res) ->
|
||||
$scope.selectedTrainingAmount = res.price
|
||||
else
|
||||
$scope.selectedTrainingAmount = null
|
||||
|
@ -1,11 +1,11 @@
|
||||
Application.Directives.directive 'coupon', [ 'Coupon', 'growl', '_t', (Coupon, growl, _t) ->
|
||||
Application.Directives.directive 'coupon', [ '$rootScope', 'Coupon', 'growl', '_t', ($rootScope, Coupon, growl, _t) ->
|
||||
{
|
||||
restrict: 'E'
|
||||
scope:
|
||||
show: '='
|
||||
coupon: '='
|
||||
total: '='
|
||||
userId: '@'
|
||||
hasSelectSlot: '='
|
||||
templateUrl: '<%= asset_path "shared/_coupon.html" %>'
|
||||
link: ($scope, element, attributes) ->
|
||||
|
||||
@ -16,15 +16,13 @@ Application.Directives.directive 'coupon', [ 'Coupon', 'growl', '_t', (Coupon, g
|
||||
# Available status are: 'pending', 'valid', 'invalid'
|
||||
$scope.status = 'pending'
|
||||
|
||||
# Binding for the code inputed
|
||||
# Binding for the code inputed (see the attached template)
|
||||
$scope.couponCode = null
|
||||
|
||||
$scope.$watch 'hasSelectSlot', (newValue) ->
|
||||
unless newValue
|
||||
$scope.coupon = null
|
||||
$scope.couponCode = null
|
||||
$scope.code.input = false
|
||||
|
||||
# Re-compute if the code can be applied when the total of the cart changes
|
||||
$scope.$watch 'total', (newValue, oldValue) ->
|
||||
if newValue and newValue != oldValue and $scope.couponCode
|
||||
$scope.validateCode()
|
||||
|
||||
##
|
||||
# Callback to validate the code
|
||||
@ -34,10 +32,13 @@ Application.Directives.directive 'coupon', [ 'Coupon', 'growl', '_t', (Coupon, g
|
||||
$scope.status = 'pending'
|
||||
$scope.coupon = null
|
||||
else
|
||||
Coupon.validate {code: $scope.couponCode, user_id: $scope.userId}, (res) ->
|
||||
Coupon.validate {code: $scope.couponCode, user_id: $scope.userId, amount: $scope.total}, (res) ->
|
||||
$scope.status = 'valid'
|
||||
$scope.coupon = res
|
||||
growl.success(_t('the_coupon_has_been_applied_you_get_PERCENT_discount', {PERCENT: res.percent_off}))
|
||||
if res.type == 'percent_off'
|
||||
growl.success(_t('the_coupon_has_been_applied_you_get_PERCENT_discount', {PERCENT: res.percent_off}))
|
||||
else
|
||||
growl.success(_t('the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY', {AMOUNT: res.amount_off, CURRENCY: $rootScope.currencySymbol}))
|
||||
, (err) ->
|
||||
$scope.status = 'invalid'
|
||||
$scope.coupon = null
|
||||
|
@ -21,7 +21,20 @@
|
||||
<span class="help-block error" ng-show="couponForm['coupon[code]'].$dirty && couponForm['coupon[code]'].$error.pattern" translate>{{ 'code_must_be_composed_of_capital_letters_digits_and_or_dashes' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': couponForm['coupon[percent_off]'].$dirty && couponForm['coupon[percent_off]'].$invalid}">
|
||||
<div class="form-group">
|
||||
<label for="coupon[type]">{{ 'kind_of_coupon' | translate }} *</label>
|
||||
<select id="coupon[type]"
|
||||
name="coupon[type]"
|
||||
class="form-control"
|
||||
ng-model="coupon.type"
|
||||
ng-disabled="mode == 'EDIT'"
|
||||
required="required">
|
||||
<option value="percent_off" translate>{{ 'percentage' }}</option>
|
||||
<option value="amount_off" translate>{{ 'amount' }}</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': couponForm['coupon[percent_off]'].$dirty && couponForm['coupon[percent_off]'].$invalid}" ng-show="coupon.type == 'percent_off'">
|
||||
<label for="coupon[percent_off]">{{ 'percent_off' | translate }} *</label>
|
||||
<div class="input-group">
|
||||
<input type="number" id="coupon[percent_off]"
|
||||
@ -31,13 +44,30 @@
|
||||
min="0"
|
||||
max="100"
|
||||
ng-disabled="mode == 'EDIT'"
|
||||
required="required"/>
|
||||
ng-required="coupon.type == 'percent_off'"/>
|
||||
<span class="input-group-addon"><i class="fa fa-percent"></i></span>
|
||||
</div>
|
||||
<span class="help-block error" ng-show="couponForm['coupon[percent_off]'].$dirty && couponForm['coupon[percent_off]'].$error.required" translate>{{ 'percent_off_is_required' }}</span>
|
||||
<span class="help-block error" ng-show="couponForm['coupon[percent_off]'].$dirty && (couponForm['coupon[percent_off]'].$error.min || couponForm['coupon[percent_off]'].$error.max)" translate>{{ 'percentage_must_be_between_0_and_100' }}</span>
|
||||
</div>
|
||||
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': couponForm['coupon[amount_off]'].$dirty && couponForm['coupon[amount_off]'].$invalid}" ng-show="coupon.type == 'amount_off'">
|
||||
<label for="coupon[amount_off]">{{ 'amount_off' | translate }} *</label>
|
||||
<div class="input-group">
|
||||
<span class="input-group-addon">{{currencySymbol}}</span>
|
||||
<input type="number" id="coupon[amount_off]"
|
||||
name="coupon[amount_off]"
|
||||
class="form-control"
|
||||
ng-model="coupon.amount_off"
|
||||
min="0"
|
||||
ng-disabled="mode == 'EDIT'"
|
||||
ng-required="coupon.type == 'amount_off'"/>
|
||||
</div>
|
||||
<span class="help-block error" ng-show="couponForm['coupon[percent_off]'].$dirty && couponForm['coupon[percent_off]'].$error.required" translate>{{ 'percent_off_is_required' }}</span>
|
||||
<span class="help-block error" ng-show="couponForm['coupon[percent_off]'].$dirty && (couponForm['coupon[percent_off]'].$error.min || couponForm['coupon[percent_off]'].$error.max)" translate>{{ 'percentage_must_be_between_0_and_100' }}</span>
|
||||
</div>
|
||||
|
||||
<div class="form-group" ng-class="{'has-error': couponForm['coupon[validity_per_user]'].$dirty && couponForm['coupon[validity_per_user]'].$invalid}">
|
||||
<label for="coupon[validity_per_user]">{{ 'validity_per_user' | translate }} *</label>
|
||||
<select id="coupon[validity_per_user]"
|
||||
|
@ -5,7 +5,7 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th translate>{{ 'name' }}</th>
|
||||
<th translate>{{ 'percentage_off' }}</th>
|
||||
<th translate>{{ 'discount' }}</th>
|
||||
<th translate>{{ 'nb_of_usages' }}</th>
|
||||
<th translate>{{ 'status' }}</th>
|
||||
<th></th>
|
||||
@ -14,7 +14,10 @@
|
||||
<tbody>
|
||||
<tr ng-repeat="coupon in coupons">
|
||||
<td>{{coupon.name}}</td>
|
||||
<td>{{coupon.percent_off}} %</td>
|
||||
<td>
|
||||
<span ng-show="coupon.type == 'percent_off'">{{coupon.percent_off}} %</span>
|
||||
<span ng-show="coupon.type == 'amount_off'">{{coupon.amount_off}} {{currencySymbol}}</span>
|
||||
</td>
|
||||
<td>{{coupon.usages}}</td>
|
||||
<td translate>{{coupon.status}}</td>
|
||||
<td>
|
||||
|
@ -13,12 +13,12 @@
|
||||
<tr><th style="width:60%"></th></tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><td translate>{{'code'}}</td><td>{{coupon.code}}</td></tr>
|
||||
<tr><td translate>{{'percent_off'}}</td><td>{{coupon.percent_off}} %</td></tr>
|
||||
<tr><td translate>{{'validity_per_user'}}</td><td translate>{{coupon.validity_per_user}}</td></tr>
|
||||
<tr><td translate>{{'valid_until'}}</td><td>{{coupon.valid_until | amDateFormat:'L'}}</td></tr>
|
||||
<tr><td translate>{{'usages'}}</td><td>{{coupon.usages}} / {{coupon.max_usages | maxCount}}</td></tr>
|
||||
<tr><td translate>{{'enabled'}}</td><td>{{coupon.active | booleanFormat}}</td></tr>
|
||||
<tr><td translate>{{'code'}}</td> <td>{{coupon.code}}</td></tr>
|
||||
<tr><td translate>{{'discount'}}</td> <td><span ng-show="coupon.type == 'percent_off'">{{coupon.percent_off}} %</span><span ng-show="coupon.type == 'amount_off'">{{coupon.amount_off}} {{currencySymbol}}</span></td></tr>
|
||||
<tr><td translate>{{'validity_per_user'}}</td> <td translate>{{coupon.validity_per_user}}</td></tr>
|
||||
<tr><td translate>{{'valid_until'}}</td> <td>{{coupon.valid_until | amDateFormat:'L'}}</td></tr>
|
||||
<tr><td translate>{{'usages'}}</td> <td>{{coupon.usages}} / {{coupon.max_usages | maxCount}}</td></tr>
|
||||
<tr><td translate>{{'enabled'}}</td> <td>{{coupon.active | booleanFormat}}</td></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
|
@ -164,7 +164,7 @@
|
||||
|
||||
<button class="btn btn-warning-full rounded btn-block text-sm" ng-click="reserveEvent()" ng-show="event.nb_free_places > 0 && !reserve.toReserve">{{ 'book' | translate }}</button>
|
||||
|
||||
<coupon show="reserve.totalSeats > 0 && ctrl.member" coupon="coupon.applied" user-id="{{ctrl.member.id}}"></coupon>
|
||||
<coupon show="reserve.totalSeats > 0 && ctrl.member" coupon="coupon.applied" total="reserve.totalNoCoupon" user-id="{{ctrl.member.id}}"></coupon>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -78,7 +78,7 @@
|
||||
<div class="clear"><a class="pull-right m-b-sm text-u-l ng-scope m-r-sm" href="#" ng-click="removeMachineSlot(machineSlot, $event)" ng-if="machineSlot.isValid" translate>{{ 'remove_this_slot' }}</a></div>
|
||||
</div>
|
||||
|
||||
<coupon show="machineSlotsValid() && (!plansAreShown || selectedPlan)" coupon="coupon.applied" has-select-slot="machineSlotsValid()" user-id="{{ctrl.member.id}}"></coupon>
|
||||
<coupon show="machineSlotsValid() && (!plansAreShown || selectedPlan)" coupon="coupon.applied" total="totalNoCoupon" user-id="{{ctrl.member.id}}"></coupon>
|
||||
|
||||
<span ng-hide="fablabWithoutPlans">
|
||||
<div ng-if="machineSlotsValid() && !ctrl.member.subscribed_plan" ng-show="!plansAreShown">
|
||||
|
@ -141,7 +141,7 @@
|
||||
<div class="font-sbold">{{ 'subscription_price' | translate }} {{selectedPlan.amount | currency}}</div>
|
||||
</div>
|
||||
|
||||
<coupon show="!ctrl.member.subscribed_plan" coupon="coupon.applied" user-id="{{ctrl.member.id}}"></coupon>
|
||||
<coupon show="!ctrl.member.subscribed_plan" coupon="coupon.applied" total="selectedPlan.amount" user-id="{{ctrl.member.id}}"></coupon>
|
||||
</div>
|
||||
|
||||
<div class="widget-footer">
|
||||
|
@ -82,7 +82,7 @@
|
||||
<a class="pull-right m-t-xs text-u-l" href="#" ng-click="removeTraining($event)" ng-if="trainingIsValid" translate>{{ 'remove_this_slot' }}</a>
|
||||
</div>
|
||||
|
||||
<coupon show="trainingIsValid && (!plansIsShow || selectedPlan)" coupon="coupon.applied" has-select-slot="trainingIsValid" user-id="{{ctrl.member.id}}"></coupon>
|
||||
<coupon show="trainingIsValid && (!plansIsShow || selectedPlan)" coupon="coupon.applied" user-id="{{ctrl.member.id}}" total="totalNoCoupon"></coupon>
|
||||
|
||||
<span ng-hide="fablabWithoutPlans">
|
||||
<div ng-if="trainingIsValid && !ctrl.member.subscribed_plan" ng-show="!plansIsShow">
|
||||
|
@ -20,7 +20,7 @@ class API::CouponsController < API::ApiController
|
||||
end
|
||||
|
||||
def validate
|
||||
@coupon = Coupon.find_by_code(params[:code])
|
||||
@coupon = Coupon.find_by(code: params[:code])
|
||||
if @coupon.nil?
|
||||
render json: {status: 'rejected'}, status: :not_found
|
||||
else
|
||||
@ -30,7 +30,8 @@ class API::CouponsController < API::ApiController
|
||||
_user_id = params[:user_id]
|
||||
end
|
||||
|
||||
status = @coupon.status(_user_id)
|
||||
amount = params[:amount].to_f * 100.0
|
||||
status = @coupon.status(_user_id, amount)
|
||||
if status != 'active'
|
||||
render json: {status: status}, status: :unprocessable_entity
|
||||
else
|
||||
@ -60,7 +61,7 @@ class API::CouponsController < API::ApiController
|
||||
def send_to
|
||||
authorize Coupon
|
||||
|
||||
@coupon = Coupon.find_by_code(params[:coupon_code])
|
||||
@coupon = Coupon.find_by(code: params[:coupon_code])
|
||||
if @coupon.nil?
|
||||
render json: {error: "no coupon with code #{params[:coupon_code]}"}, status: :not_found
|
||||
else
|
||||
@ -78,7 +79,14 @@ class API::CouponsController < API::ApiController
|
||||
end
|
||||
|
||||
def coupon_params
|
||||
params.require(:coupon).permit(:name, :code, :percent_off, :validity_per_user, :valid_until, :max_usages, :active)
|
||||
if @parameters
|
||||
@parameters
|
||||
else
|
||||
@parameters = params
|
||||
@parameters[:coupon][:amount_off] = @parameters[:coupon][:amount_off].to_i * 100.0 if @parameters[:coupon][:amount_off]
|
||||
|
||||
@parameters = @parameters.require(:coupon).permit(:name, :code, :percent_off, :amount_off, :validity_per_user, :valid_until, :max_usages, :active)
|
||||
end
|
||||
end
|
||||
|
||||
def coupon_editable_params
|
||||
|
@ -9,7 +9,12 @@ class API::FeedsController < API::ApiController
|
||||
limit = 3
|
||||
end
|
||||
from_account = Setting.find_by(name: 'twitter_name').try(:value) || ENV['TWITTER_NAME']
|
||||
@tweet_news = Feed.twitter.user_timeline(from_account, {count: limit})
|
||||
begin
|
||||
@tweet_news = Feed.twitter.user_timeline(from_account, {count: limit})
|
||||
rescue Twitter::Error::BadRequest => e
|
||||
STDERR.puts "[WARNING] Unable to retrieve the twitter feed, please check your ENV configuration. Details: #{e.message}"
|
||||
render status: :no_content
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
@ -145,7 +145,7 @@ class API::MembersController < API::ApiController
|
||||
|
||||
token = params.require(:user).permit(:auth_token)[:auth_token]
|
||||
|
||||
@account = User.find_by_auth_token(token)
|
||||
@account = User.find_by(auth_token: token)
|
||||
if @account
|
||||
@flow_worker = MembersProcessor.new(@account)
|
||||
begin
|
||||
|
@ -92,8 +92,6 @@
|
||||
plan_file_attributes: [:id, :attachment, :_destroy],
|
||||
prices_attributes: [:id, :amount]
|
||||
)
|
||||
|
||||
@parameters
|
||||
end
|
||||
end
|
||||
end
|
||||
|
@ -41,7 +41,7 @@ class API::ProjectsController < API::ApiController
|
||||
end
|
||||
|
||||
def collaborator_valid
|
||||
project_user = ProjectUser.find_by_valid_token params[:valid_token]
|
||||
project_user = ProjectUser.find_by(valid_token: params[:valid_token])
|
||||
if project_user
|
||||
project_user.update(is_valid: true, valid_token: '')
|
||||
redirect_to "/#!/projects/#{project_user.project.id}" and return
|
||||
|
@ -22,7 +22,7 @@ class API::StatisticsController < API::ApiController
|
||||
|
||||
# run additional custom aggregations, if any
|
||||
if statistic_type and start_date and end_date
|
||||
stat_index = StatisticIndex.find_by_es_type_key("#{path}")
|
||||
stat_index = StatisticIndex.find_by(es_type_key: "#{path}")
|
||||
stat_type = StatisticType.where(statistic_index_id: stat_index.id, key: statistic_type).first
|
||||
client = Elasticsearch::Model.client
|
||||
stat_type.statistic_custom_aggregations.each do |custom|
|
||||
|
@ -8,10 +8,9 @@ class Coupon < ActiveRecord::Base
|
||||
validates :code, presence: true
|
||||
validates :code, format: { with: /\A[A-Z0-9\-]+\z/ ,message: 'only caps letters, numbers, and dashes'}
|
||||
validates :code, uniqueness: true
|
||||
validates :percent_off, presence: true
|
||||
validates :percent_off, :inclusion => 0..100
|
||||
validates :validity_per_user, presence: true
|
||||
validates :validity_per_user, inclusion: { in: %w(once forever) }
|
||||
validates_with CouponDiscountValidator
|
||||
|
||||
def safe_destroy
|
||||
if self.invoices.size == 0
|
||||
@ -27,12 +26,15 @@ class Coupon < ActiveRecord::Base
|
||||
# - may has expired because the validity date has been reached,
|
||||
# - may have been used the maximum number of times it was allowed
|
||||
# - may have already been used by the provided user, if the coupon is configured to allow only one use per user,
|
||||
# - may exceed the current cart's total amount, if the coupon is configured to discount an amount (and not a percentage)
|
||||
# - may be available for use
|
||||
# @param [user_id] {Number} if provided and if the current coupon's validity_per_user == 'once', check that the coupon
|
||||
# was already used by the provided user
|
||||
# @param [amount] {Number} if provided and if the current coupon's type == 'amont_off' check that the coupon
|
||||
# does not exceed the cart total price
|
||||
# @return {String} status identifier
|
||||
##
|
||||
def status(user_id = nil)
|
||||
def status(user_id = nil, amount = nil)
|
||||
if not active?
|
||||
'disabled'
|
||||
elsif (!valid_until.nil?) and valid_until.at_end_of_day < DateTime.now
|
||||
@ -41,11 +43,21 @@ class Coupon < ActiveRecord::Base
|
||||
'sold_out'
|
||||
elsif (!user_id.nil?) and validity_per_user == 'once' and users_ids.include?(user_id.to_i)
|
||||
'already_used'
|
||||
elsif (!amount.nil?) and type == 'amount_off' and amount_off > amount.to_f
|
||||
'amount_exceeded'
|
||||
else
|
||||
'active'
|
||||
end
|
||||
end
|
||||
|
||||
def type
|
||||
if amount_off.nil? and !percent_off.nil?
|
||||
'percent_off'
|
||||
elsif percent_off.nil? and !amount_off.nil?
|
||||
'amount_off'
|
||||
end
|
||||
end
|
||||
|
||||
def users
|
||||
self.invoices.map do |i|
|
||||
i.user
|
||||
|
@ -149,7 +149,14 @@ class Invoice < ActiveRecord::Base
|
||||
end
|
||||
# handle coupon
|
||||
unless avoir.coupon_id.nil?
|
||||
discount = avoir.total * avoir.coupon.percent_off / 100.0
|
||||
discount = avoir.total
|
||||
if avoir.coupon.type == 'percent_off'
|
||||
discount = avoir.total * avoir.coupon.percent_off / 100.0
|
||||
elsif avoir.coupon.type == 'amount_off'
|
||||
discount = avoir.coupon.amount_off
|
||||
else
|
||||
raise InvalidCouponError
|
||||
end
|
||||
avoir.total -= discount
|
||||
end
|
||||
avoir
|
||||
|
@ -45,7 +45,7 @@ class Price < ActiveRecord::Base
|
||||
if machine_credit
|
||||
hours_available = machine_credit.hours
|
||||
if !new_plan_being_bought
|
||||
user_credit = user.users_credits.find_by_credit_id(machine_credit.id)
|
||||
user_credit = user.users_credits.find_by(credit_id: machine_credit.id)
|
||||
if user_credit
|
||||
hours_available = machine_credit.hours - user_credit.hours_used
|
||||
end
|
||||
@ -111,13 +111,11 @@ class Price < ActiveRecord::Base
|
||||
end
|
||||
|
||||
# === apply Coupon if any ===
|
||||
unless coupon_code.nil?
|
||||
_coupon = Coupon.find_by_code(coupon_code)
|
||||
_amount = _amount - (_amount * _coupon.percent_off / 100.0)
|
||||
end
|
||||
_amount_no_coupon = _amount
|
||||
_amount = CouponApplyService.new.(_amount, coupon_code)
|
||||
|
||||
# return result
|
||||
{elements: _elements, total: _amount}
|
||||
{elements: _elements, total: _amount, before_coupon: _amount_no_coupon}
|
||||
end
|
||||
|
||||
private
|
||||
|
@ -134,16 +134,25 @@ class Reservation < ActiveRecord::Base
|
||||
|
||||
# === Coupon ===
|
||||
unless coupon_code.nil?
|
||||
cp = Coupon.find_by_code(coupon_code)
|
||||
if not cp.nil? and cp.status(user.id) == 'active'
|
||||
@coupon = cp
|
||||
@coupon = Coupon.find_by(code: coupon_code)
|
||||
if not @coupon.nil? and @coupon.status(user.id) == 'active'
|
||||
total = invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+)
|
||||
|
||||
discount = 0
|
||||
if @coupon.type == 'percent_off'
|
||||
discount = (total * @coupon.percent_off / 100).to_i
|
||||
elsif @coupon.type == 'amount_off'
|
||||
discount = @coupon.amount_off
|
||||
else
|
||||
raise InvalidCouponError
|
||||
end
|
||||
|
||||
unless on_site
|
||||
invoice_items << Stripe::InvoiceItem.create(
|
||||
customer: user.stp_customer_id,
|
||||
amount: -(total * cp.percent_off / 100).to_i,
|
||||
amount: -discount,
|
||||
currency: Rails.application.secrets.stripe_currency,
|
||||
description: "coupon #{cp.code} - reservation"
|
||||
description: "coupon #{@coupon.code} - reservation"
|
||||
)
|
||||
end
|
||||
else
|
||||
@ -395,7 +404,7 @@ class Reservation < ActiveRecord::Base
|
||||
total += plan.amount
|
||||
end
|
||||
if @coupon
|
||||
total = (total - (total * @coupon.percent_off / 100.0)).to_i
|
||||
total = CouponApplyService.new.(total, @coupon, user.id)
|
||||
end
|
||||
wallet_amount = (user.wallet.amount * 100).to_i
|
||||
|
||||
@ -427,9 +436,9 @@ class Reservation < ActiveRecord::Base
|
||||
total = invoice.invoice_items.map(&:amount).map(&:to_i).reduce(:+)
|
||||
|
||||
unless coupon_code.nil?
|
||||
cp = Coupon.find_by_code(coupon_code)
|
||||
cp = Coupon.find_by(code: coupon_code)
|
||||
if not cp.nil? and cp.status(user.id) == 'active'
|
||||
total = total - (total * cp.percent_off / 100.0)
|
||||
total = CouponApplyService.new.(total, cp, user.id)
|
||||
self.invoice.coupon_id = cp.id
|
||||
else
|
||||
raise InvalidCouponError
|
||||
|
@ -25,15 +25,24 @@ class Subscription < ActiveRecord::Base
|
||||
invoice_items = []
|
||||
|
||||
unless coupon_code.nil?
|
||||
cp = Coupon.find_by_code(coupon_code)
|
||||
if not cp.nil? and cp.status(user.id) == 'active'
|
||||
@coupon = cp
|
||||
@coupon = Coupon.find_by(code: coupon_code)
|
||||
if not @coupon.nil? and @coupon.status(user.id) == 'active'
|
||||
total = plan.amount
|
||||
|
||||
discount = 0
|
||||
if @coupon.type == 'percent_off'
|
||||
discount = (total * @coupon.percent_off / 100).to_i
|
||||
elsif @coupon.type == 'amount_off'
|
||||
discount = @coupon.amount_off
|
||||
else
|
||||
raise InvalidCouponError
|
||||
end
|
||||
|
||||
invoice_items << Stripe::InvoiceItem.create(
|
||||
customer: user.stp_customer_id,
|
||||
amount: -(total * cp.percent_off / 100.0).to_i,
|
||||
amount: -discount,
|
||||
currency: Rails.application.secrets.stripe_currency,
|
||||
description: "coupon #{cp.code} - subscription"
|
||||
description: "coupon #{@coupon.code} - subscription"
|
||||
)
|
||||
else
|
||||
raise InvalidCouponError
|
||||
@ -159,11 +168,11 @@ class Subscription < ActiveRecord::Base
|
||||
total = plan.amount
|
||||
|
||||
unless coupon_code.nil?
|
||||
cp = Coupon.find_by_code(coupon_code)
|
||||
if not cp.nil? and cp.status(user.id) == 'active'
|
||||
@coupon = cp
|
||||
coupon_id = cp.id
|
||||
total = plan.amount - (plan.amount * cp.percent_off / 100.0)
|
||||
@coupon = Coupon.find_by(code: coupon_code)
|
||||
|
||||
unless @coupon.nil?
|
||||
total = CouponApplyService.new.(plan.amount, @coupon, user.id)
|
||||
coupon_id = @coupon.id
|
||||
end
|
||||
end
|
||||
|
||||
@ -293,7 +302,7 @@ class Subscription < ActiveRecord::Base
|
||||
def get_wallet_amount_debit
|
||||
total = plan.amount
|
||||
if @coupon
|
||||
total = (total - (total * @coupon.percent_off / 100.0)).to_i
|
||||
total = CouponApplyService.new.(total, @coupon, user.id)
|
||||
end
|
||||
wallet_amount = (user.wallet.amount * 100).to_i
|
||||
return wallet_amount >= total ? total : wallet_amount
|
||||
|
@ -131,7 +131,7 @@ class User < ActiveRecord::Base
|
||||
end
|
||||
json.machine_credits machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by_user_id(id).hours_used
|
||||
json.hours_used mc.users_credits.find_by(user_id: id).hours_used
|
||||
end
|
||||
json.last_sign_in_at last_sign_in_at.iso8601 if last_sign_in_at
|
||||
end
|
||||
|
@ -3,6 +3,7 @@ module PDF
|
||||
class Invoice < Prawn::Document
|
||||
require 'stringio'
|
||||
include ActionView::Helpers::NumberHelper
|
||||
include ApplicationHelper
|
||||
|
||||
def initialize(invoice)
|
||||
super(:margin => 70)
|
||||
@ -143,11 +144,25 @@ module PDF
|
||||
# subtract the coupon, if any
|
||||
unless invoice.coupon_id.nil?
|
||||
cp = invoice.coupon
|
||||
discount = total_calc * cp.percent_off / 100.0
|
||||
discount = 0
|
||||
if cp.type == 'percent_off'
|
||||
discount = total_calc * cp.percent_off / 100.0
|
||||
elsif cp.type == 'amount_off'
|
||||
discount = cp.amount_off / 100.00
|
||||
else
|
||||
raise InvalidCouponError
|
||||
end
|
||||
|
||||
total_calc = total_calc - discount
|
||||
|
||||
# discount textual description
|
||||
literal_discount = cp.percent_off
|
||||
if cp.type == 'amount_off'
|
||||
literal_discount = number_to_currency(discount)
|
||||
end
|
||||
|
||||
# add a row for the coupon
|
||||
data += [ [I18n.t('invoices.coupon_CODE_discount_of_PERCENT', CODE: cp.code, PERCENT: cp.percent_off), number_to_currency(-discount)] ]
|
||||
data += [ [_t('invoices.coupon_CODE_discount_of_DISCOUNT', {CODE: cp.code, DISCOUNT: literal_discount, TYPE: cp.type}), number_to_currency(-discount)] ]
|
||||
end
|
||||
|
||||
# total verification
|
||||
|
37
app/services/coupon_apply_service.rb
Normal file
37
app/services/coupon_apply_service.rb
Normal file
@ -0,0 +1,37 @@
|
||||
class CouponApplyService
|
||||
##
|
||||
# Apply the provided coupon, if active, to the given price. Usability tests will be run depending on the
|
||||
# provided parameters.
|
||||
# If no coupon/coupon code or if the code does not match, return origin price without change
|
||||
#
|
||||
# @param total {Number} invoice total, before any coupon is applied
|
||||
# @param coupon {String|Coupon} Coupon's code OR Coupon object
|
||||
# @param user_id {Number} user's id against the coupon will be tested for usability
|
||||
# @return {Number}
|
||||
##
|
||||
def call(total, coupon, user_id = nil)
|
||||
price = total
|
||||
|
||||
_coupon = nil
|
||||
if coupon.instance_of? Coupon
|
||||
_coupon = coupon
|
||||
elsif coupon.instance_of? String
|
||||
_coupon = Coupon.find_by(code: coupon)
|
||||
end
|
||||
|
||||
unless _coupon.nil?
|
||||
if _coupon.status(user_id, total) == 'active'
|
||||
if _coupon.type == 'percent_off'
|
||||
price = price - (price * _coupon.percent_off / 100.0)
|
||||
elsif _coupon.type == 'amount_off'
|
||||
# do not apply cash coupon unless it has a lower amount that the total price
|
||||
if _coupon.amount_off <= price
|
||||
price -= _coupon.amount_off
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
price
|
||||
end
|
||||
end
|
@ -127,7 +127,7 @@ class StatisticService
|
||||
if sub
|
||||
ca = i.amount.to_i / 100.0
|
||||
unless i.invoice.coupon_id.nil?
|
||||
ca = ca - ( ca * i.invoice.coupon.percent_off / 100.0 )
|
||||
ca = CouponApplyService.new(ca, i.invoice.coupon)
|
||||
end
|
||||
u = sub.user
|
||||
p = sub.plan
|
||||
@ -353,7 +353,7 @@ class StatisticService
|
||||
end
|
||||
# subtract coupon discount from invoices and refunds
|
||||
unless invoice.coupon_id.nil?
|
||||
ca = ca - ( ca * invoice.coupon.percent_off / 100.0 )
|
||||
ca = CouponApplyService.new(ca, invoice.coupon)
|
||||
end
|
||||
# divide the result by 100 to convert from centimes to monetary unit
|
||||
ca == 0 ? ca : ca / 100.0
|
||||
@ -366,7 +366,7 @@ class StatisticService
|
||||
end
|
||||
# subtract coupon discount from the refund
|
||||
unless invoice.coupon_id.nil?
|
||||
ca = ca - ( ca * invoice.coupon.percent_off / 100.0 )
|
||||
ca = CouponApplyService.new(ca, invoice.coupon)
|
||||
end
|
||||
ca == 0 ? ca : ca / 100.0
|
||||
end
|
||||
|
15
app/validators/coupon_discount_validator.rb
Normal file
15
app/validators/coupon_discount_validator.rb
Normal file
@ -0,0 +1,15 @@
|
||||
class CouponDiscountValidator < ActiveModel::Validator
|
||||
def validate(record)
|
||||
if !record.percent_off.nil?
|
||||
unless [0..100].include? record.percent_off
|
||||
record.errors[:percent_off] << 'Percentage must be included between 0 and 100'
|
||||
end
|
||||
elsif !record.amount_off.nil?
|
||||
unless record.amount_off > 0
|
||||
record.errors[:amount_off] << I18n.t('errors.messages.greater_than_or_equal_to', count: 0)
|
||||
end
|
||||
else
|
||||
record.errors[:percent_off] << 'cannot be blank when amount_off is blank too'
|
||||
end
|
||||
end
|
||||
end
|
@ -1,3 +1,4 @@
|
||||
json.extract! coupon, :id, :name, :code, :percent_off, :valid_until, :validity_per_user, :max_usages, :active, :created_at
|
||||
json.extract! coupon, :id, :name, :code, :type, :percent_off, :valid_until, :validity_per_user, :max_usages, :active, :created_at
|
||||
json.amount_off (coupon.amount_off / 100.00) unless coupon.amount_off.nil?
|
||||
json.usages coupon.invoices.count
|
||||
json.status coupon.status
|
@ -1 +1,2 @@
|
||||
json.extract! @coupon, :id, :code, :percent_off
|
||||
json.extract! @coupon, :id, :code, :type, :percent_off
|
||||
json.amount_off (@coupon.amount_off / 100.00) unless @coupon.amount_off.nil?
|
@ -54,7 +54,7 @@ json.array!(@members) do |member|
|
||||
|
||||
json.machine_credits member.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by_user_id(member.id).hours_used
|
||||
json.hours_used mc.users_credits.find_by(user_id: member.id).hours_used
|
||||
end if attribute_requested?(@requested_attributes, 'credits') or attribute_requested?(@requested_attributes, 'machine_credits')
|
||||
|
||||
json.tags member.tags do |t|
|
||||
|
@ -69,7 +69,7 @@ json.training_credits @member.training_credits do |tc|
|
||||
end
|
||||
json.machine_credits @member.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by_user_id(@member.id).hours_used
|
||||
json.hours_used mc.users_credits.find_by(user_id: @member.id).hours_used
|
||||
end
|
||||
json.last_sign_in_at @member.last_sign_in_at.iso8601 if @member.last_sign_in_at
|
||||
json.all_projects @member.all_projects do |project|
|
||||
|
@ -1,4 +1,5 @@
|
||||
json.price @amount[:total] / 100.00
|
||||
json.price_without_coupon @amount[:before_coupon] / 100.00
|
||||
json.details do
|
||||
json.slots @amount[:elements][:slots] do |slot|
|
||||
json.start_at slot[:start_at]
|
||||
|
@ -10,7 +10,7 @@ json.user do
|
||||
end
|
||||
json.machine_credits @reservation.user.machine_credits do |mc|
|
||||
json.machine_id mc.creditable_id
|
||||
json.hours_used mc.users_credits.find_by_user_id(@reservation.user_id).hours_used
|
||||
json.hours_used mc.users_credits.find_by(user_id: @reservation.user_id).hours_used
|
||||
end
|
||||
end
|
||||
json.message @reservation.message
|
||||
|
@ -1,10 +1,18 @@
|
||||
<%= render 'notifications_mailer/shared/hello', recipient: @recipient %>
|
||||
|
||||
<p><%= t('.body.enjoy_a_discount_of_PERCENT_with_code_CODE',
|
||||
PERCENT: @attached_object.percent_off,
|
||||
CODE: @attached_object.code
|
||||
) %>
|
||||
</p>
|
||||
<% if @attached_object.type == 'percent_off' %>
|
||||
<p><%= t('.body.enjoy_a_discount_of_PERCENT_with_code_CODE',
|
||||
PERCENT: @attached_object.percent_off,
|
||||
CODE: @attached_object.code
|
||||
) %>
|
||||
</p>
|
||||
<% else %>
|
||||
<p><%= t('.body.enjoy_a_discount_of_AMOUNT_with_code_CODE',
|
||||
AMOUNT: number_to_currency(@attached_object.amount_off / 100.00),
|
||||
CODE: @attached_object.code
|
||||
) %>
|
||||
</p>
|
||||
<% end %>
|
||||
|
||||
<%
|
||||
# we must tell the use if he could use the code just once or many times (in case we won't specify)
|
||||
@ -21,6 +29,7 @@
|
||||
<%= _t('.body.this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases',
|
||||
{
|
||||
USAGE: usages,
|
||||
TYPE: @attached_object.type,
|
||||
DATE: @attached_object.valid_until.nil? ? 'NO-DATE' : I18n.l(@attached_object.valid_until.to_date)
|
||||
})
|
||||
# messageFormat
|
||||
|
@ -16,7 +16,7 @@ class ReservationReminderWorker
|
||||
already_sent = Notification.where(
|
||||
attached_object_type: Reservation.name,
|
||||
attached_object_id: r.id,
|
||||
notification_type_id: NotificationType.find_by_name('notify_member_reservation_reminder')
|
||||
notification_type_id: NotificationType.find_by(name: 'notify_member_reservation_reminder')
|
||||
).count
|
||||
unless already_sent > 0
|
||||
NotificationCenter.call type: 'notify_member_reservation_reminder',
|
||||
|
@ -20,8 +20,14 @@ class StripeWorker
|
||||
stp_coupon = {
|
||||
id: coupon.code,
|
||||
duration: coupon.validity_per_user,
|
||||
percent_off: coupon.percent_off,
|
||||
}
|
||||
if coupon.type == 'percent_off'
|
||||
stp_coupon[:percent_off] = coupon.percent_off
|
||||
elsif coupon.type == 'amount_off'
|
||||
stp_coupon[:amount_off] = coupon.amount_off
|
||||
stp_coupon[:currency] = Rails.application.secrets.stripe_currency
|
||||
end
|
||||
|
||||
unless coupon.valid_until.nil?
|
||||
stp_coupon[:redeem_by] = coupon.valid_until.to_i
|
||||
end
|
||||
|
@ -164,7 +164,7 @@ en:
|
||||
unable_to_delete_the_specified_subscription_an_error_occurred: "Unable to delete the specified subscription, an error occurred."
|
||||
coupons: "Coupons"
|
||||
list_of_the_coupons: "List of the coupons"
|
||||
percentage_off: "Percentage off"
|
||||
discount: "Discount"
|
||||
nb_of_usages: "Number of usages"
|
||||
status: "Status"
|
||||
add_a_new_coupon: "Add a new coupon"
|
||||
|
@ -164,7 +164,7 @@ fr:
|
||||
unable_to_delete_the_specified_subscription_an_error_occurred: "Impossible de supprimer l'abonnement spécifié, une erreur s'est produite."
|
||||
coupons: "Codes promotionnels"
|
||||
list_of_the_coupons: "Liste des codes promotionnels"
|
||||
percentage_off: "Pourcentage de réduction"
|
||||
discount: "Réduction"
|
||||
nb_of_usages: "Nombre d'utilisations"
|
||||
status: "Statut"
|
||||
add_a_new_coupon: "Ajouter un code promotionnel"
|
||||
|
@ -346,6 +346,10 @@ en:
|
||||
code: "Code"
|
||||
code_is_required: "Code is required."
|
||||
code_must_be_composed_of_capital_letters_digits_and_or_dashes: "The code must be composed of capital letters, digits and/or dashes."
|
||||
kind_of_coupon: "Kind of coupon"
|
||||
percentage: "Percentage"
|
||||
amount: "Amount"
|
||||
amount_off: "Amount off"
|
||||
percent_off: "Percentage off"
|
||||
percent_off_is_required: "Percentage off is required."
|
||||
percentage_must_be_between_0_and_100: "Percentage must be between 0 and 100."
|
||||
@ -363,9 +367,12 @@ en:
|
||||
# coupon (input zone for users)
|
||||
i_have_a_coupon: "I have a coupon!"
|
||||
code_: "Code:"
|
||||
the_coupon_has_been_applied_you_get_PERCENT_discount: "The coupon has been applied. You get {{PERCENT}}% discount." # angular interpolation
|
||||
the_coupon_has_been_applied_you_get_PERCENT_discount: "The coupon has been applied. You get a {{PERCENT}}% discount." # angular interpolation
|
||||
the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY: "The coupon has been applied. You get a discount of {{AMOUNT}} {{CURRENCY}}." # angular interpolation
|
||||
unable_to_apply_the_coupon_because_disabled: "Unable to apply the coupon: this code was disabled."
|
||||
unable_to_apply_the_coupon_because_expired: "Unable to apply the coupon: this code has expired."
|
||||
unable_to_apply_the_coupon_because_sold_out: "Unable to apply the coupon: this code reached its quota."
|
||||
unable_to_apply_the_coupon_because_already_used: "Unable to apply the coupon: you have already used this code once before."
|
||||
unable_to_apply_the_coupon_because_amount_exceeded: "Unable to apply the coupon: the discount exceed the total amount of this purchase."
|
||||
unable_to_apply_the_coupon_because_undefined: "Unable to apply the coupon: an unexpected error occurred, please contact the Fablab's manager."
|
||||
unable_to_apply_the_coupon_because_rejected: "This code does not exists."
|
||||
|
@ -346,6 +346,10 @@ fr:
|
||||
code: "Code"
|
||||
code_is_required: "Le code est requis."
|
||||
code_must_be_composed_of_capital_letters_digits_and_or_dashes: "Le code doit être composé de lettres majuscules, de chiffres et/ou de tirets."
|
||||
kind_of_coupon: "Type de réduction"
|
||||
percentage: "Pourcentage"
|
||||
amount: "Montant"
|
||||
amount_off: "Montant de la réduction"
|
||||
percent_off: "Pourcentage de réduction"
|
||||
percent_off_is_required: "Le pourcentage de réduction est requis."
|
||||
percentage_must_be_between_0_and_100: "Le pourcentage doit être compris entre 0 et 100."
|
||||
@ -364,8 +368,11 @@ fr:
|
||||
i_have_a_coupon: "J'ai un code promo !"
|
||||
code_: "Code :"
|
||||
the_coupon_has_been_applied_you_get_PERCENT_discount: "Le code promo a bien été appliqué. Vous bénéficiez d'une remise de {{PERCENT}} %." # angular interpolation
|
||||
the_coupon_has_been_applied_you_get_AMOUNT_CURRENCY: "Le code promo a bien été appliqué. Vous bénéficiez d'une remise de {{AMOUNT}} {{CURRENCY}}." # angular interpolation
|
||||
unable_to_apply_the_coupon_because_disabled: "Impossible d'appliquer la réduction : ce code promo a été désactivé."
|
||||
unable_to_apply_the_coupon_because_expired: "Impossible d'appliquer la réduction : ce code promo a expiré."
|
||||
unable_to_apply_the_coupon_because_sold_out: "Impossible d'appliquer la réduction : ce code promo a atteint son quota."
|
||||
unable_to_apply_the_coupon_because_already_used: "Impossible d'appliquer la réduction : vous avez déjà utilisé ce code promo par le passé."
|
||||
unable_to_apply_the_coupon_because_amount_exceeded: "Impossible d'appliquer la réduction : la réduction dépasse le total de cet achat."
|
||||
unable_to_apply_the_coupon_because_undefined: "Impossible d'appliquer la réduction : une erreur inattendue s'est produite, veuillez contacter le gestionnaire du Fablab."
|
||||
unable_to_apply_the_coupon_because_rejected: "Ce code promo n'existe pas."
|
@ -87,7 +87,7 @@ en:
|
||||
one: "One %{NAME} ticket"
|
||||
other: "%{count} %{NAME} tickets"
|
||||
reservation_other: "Reservation (other)"
|
||||
coupon_CODE_discount_of_PERCENT: "Coupon %{CODE}: discount of %{PERCENT}%"
|
||||
coupon_CODE_discount_of_DISCOUNT: "Coupon {CODE}: discount of {DISCOUNT}{TYPE, select, percent_off{%} other{}}" # messageFormat interpolation
|
||||
total_including_all_taxes: "Total incl. all taxes"
|
||||
including_VAT_RATE: "Including VAT %{RATE}%"
|
||||
including_total_excluding_taxes: "Including Total excl. taxes"
|
||||
|
@ -87,7 +87,7 @@ fr:
|
||||
one: "Une place %{NAME}"
|
||||
other: "%{count} places %{NAME}"
|
||||
reservation_other: "Réservation (autre)"
|
||||
coupon_CODE_discount_of_PERCENT: "Code %{CODE} : remise de %{PERCENT} %"
|
||||
coupon_CODE_discount_of_DISCOUNT: "Code {CODE} : remise de {DISCOUNT} {TYPE, select, percent_off{%} other{}}" # messageFormat interpolation
|
||||
total_including_all_taxes: "Total TTC"
|
||||
including_VAT_RATE: "Dont TVA %{RATE}%"
|
||||
including_total_excluding_taxes: "Dont total HT"
|
||||
|
@ -278,7 +278,8 @@ en:
|
||||
subject: "Coupon"
|
||||
body:
|
||||
enjoy_a_discount_of_PERCENT_with_code_CODE: "Enjoy a discount of %{PERCENT}% on the whole site with the code %{CODE}."
|
||||
this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "This coupon is valid {USAGE, plural, =1{just once} other{many times}}: for all your purchases, from now {DATE, select, NO-DATE{and without time limit} other{and until {DATE}}}."
|
||||
enjoy_a_discount_of_AMOUNT_with_code_CODE: "Enjoy a discount of %{AMOUNT} on the whole site with the code %{CODE}."
|
||||
this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "This coupon is valid {USAGE, plural, =1{just once} other{many times}}: for all your purchases {TYPE, select, amount_off{at least equal to the amount of the coupon} other{}}, from now {DATE, select, NO-DATE{and without time limit} other{and until {DATE}}}."
|
||||
|
||||
shared:
|
||||
hello: "Hello %{user_name}"
|
||||
|
@ -278,7 +278,8 @@ fr:
|
||||
subject: "Code promo"
|
||||
body:
|
||||
enjoy_a_discount_of_PERCENT_with_code_CODE: "Bénéficiez d'une remise de %{PERCENT} % sur tout le site en utilisant le code promo %{CODE}."
|
||||
this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "Ce code promo est valable {USAGE, plural, =1{une seule fois} other{plusieurs fois}} : pour tous vos achats, dès maintenant {DATE, select, NO-DATE{et sans limitation de durée} other{et jusqu'au {DATE}}}."
|
||||
enjoy_a_discount_of_AMOUNT_with_code_CODE: "Bénéficiez d'une remise de %{AMOUNT} sur tout le site en utilisant le code promo %{CODE}."
|
||||
this_coupon_is_valid_USAGE_times_until_DATE_for_all_your_purchases: "Ce code promo est valable {USAGE, plural, =1{une seule fois} other{plusieurs fois}} : pour tous vos achats {TYPE, select, amount_off{dont le montant est au moins égal à celui du code promo} other{}}, dès maintenant {DATE, select, NO-DATE{et sans limitation de durée} other{et jusqu'au {DATE}}}."
|
||||
|
||||
shared:
|
||||
hello: "Bonjour %{user_name}"
|
||||
|
@ -28,7 +28,7 @@ class MigrateEventReducedAmountToPriceCategory < ActiveRecord::Migration
|
||||
end
|
||||
|
||||
def down
|
||||
pc = PriceCategory.find_by_name(I18n.t('price_category.reduced_fare'))
|
||||
pc = PriceCategory.find_by(name: I18n.t('price_category.reduced_fare'))
|
||||
EventPriceCategory.where(price_category_id: pc.id).each do |epc|
|
||||
epc.event.update_column(:reduced_amount, epc.amount)
|
||||
|
||||
|
@ -1,7 +1,7 @@
|
||||
class InsertCustomAggregations < ActiveRecord::Migration
|
||||
def up
|
||||
# available reservations hours for machines
|
||||
machine = StatisticIndex.find_by_es_type_key('machine')
|
||||
machine = StatisticIndex.find_by(es_type_key: 'machine')
|
||||
machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: machine.id)
|
||||
|
||||
available_hours = StatisticCustomAggregation.new({
|
||||
@ -14,7 +14,7 @@ class InsertCustomAggregations < ActiveRecord::Migration
|
||||
available_hours.save!
|
||||
|
||||
# available training tickets
|
||||
training = StatisticIndex.find_by_es_type_key('training')
|
||||
training = StatisticIndex.find_by(es_type_key: 'training')
|
||||
training_bookings = StatisticType.find_by(key: 'booking', statistic_index_id: training.id)
|
||||
|
||||
available_tickets = StatisticCustomAggregation.new({
|
||||
@ -29,12 +29,12 @@ class InsertCustomAggregations < ActiveRecord::Migration
|
||||
|
||||
def down
|
||||
|
||||
machine = StatisticIndex.find_by_es_type_key('machine')
|
||||
machine = StatisticIndex.find_by(es_type_key: 'machine')
|
||||
machine_hours = StatisticType.find_by(key: 'hour', statistic_index_id: machine.id)
|
||||
|
||||
StatisticCustomAggregation.where(field: 'available_hours', statistic_type_id: machine_hours.id).first.destroy!
|
||||
|
||||
training = StatisticIndex.find_by_es_type_key('training')
|
||||
training = StatisticIndex.find_by(es_type_key: 'training')
|
||||
training_bookings = StatisticType.find_by(key: 'booking', statistic_index_id: training.id)
|
||||
|
||||
StatisticCustomAggregation.where(field: 'available_tickets', statistic_type_id: training_bookings.id).first.destroy!
|
||||
|
5
db/migrate/20161123104604_add_amount_off_to_coupons.rb
Normal file
5
db/migrate/20161123104604_add_amount_off_to_coupons.rb
Normal file
@ -0,0 +1,5 @@
|
||||
class AddAmountOffToCoupons < ActiveRecord::Migration
|
||||
def change
|
||||
add_column :coupons, :amount_off, :integer
|
||||
end
|
||||
end
|
@ -11,7 +11,7 @@
|
||||
#
|
||||
# It's strongly recommended that you check this file into your version control system.
|
||||
|
||||
ActiveRecord::Schema.define(version: 20160915105234) do
|
||||
ActiveRecord::Schema.define(version: 20161123104604) do
|
||||
|
||||
# These are extensions that must be enabled in order to support this database
|
||||
enable_extension "plpgsql"
|
||||
@ -114,6 +114,7 @@ ActiveRecord::Schema.define(version: 20160915105234) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "validity_per_user"
|
||||
t.integer "amount_off"
|
||||
end
|
||||
|
||||
create_table "credits", force: :cascade do |t|
|
||||
@ -319,6 +320,7 @@ ActiveRecord::Schema.define(version: 20160915105234) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "profile_url"
|
||||
t.string "logout_endpoint"
|
||||
end
|
||||
|
||||
create_table "offer_days", force: :cascade do |t|
|
||||
|
@ -2,7 +2,7 @@ namespace :fablab do
|
||||
# desc "Get all stripe plans and create in fablab app"
|
||||
# task stripe_plan: :environment do
|
||||
# Stripe::Plan.all.data.each do |plan|
|
||||
# unless Plan.find_by_stp_plan_id(plan.id)
|
||||
# unless Plan.find_by(stp_plan_id: plan.id)
|
||||
# group = Group.friendly.find(plan.id.split('-').first)
|
||||
# if group
|
||||
# Plan.create(stp_plan_id: plan.id, name: plan.name, amount: plan.amount, interval: plan.interval, group_id: group.id, skip_create_stripe_plan: true)
|
||||
|
10
test/fixtures/availabilities.yml
vendored
10
test/fixtures/availabilities.yml
vendored
@ -159,3 +159,13 @@ availability_16:
|
||||
updated_at: 2016-04-04 15:44:04.023557000 Z
|
||||
nb_total_places:
|
||||
destroying: false
|
||||
|
||||
availability_17:
|
||||
id: 17
|
||||
start_at: <%= 10.days.from_now.utc.change({hour: 10}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
end_at: <%= 12.days.from_now.utc.change({hour: 18}).strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
available_type: machines
|
||||
created_at: 2016-04-04 15:44:04.023557000 Z
|
||||
updated_at: 2016-04-04 15:44:04.023557000 Z
|
||||
nb_total_places:
|
||||
destroying: false
|
9
test/fixtures/coupons.yml
vendored
9
test/fixtures/coupons.yml
vendored
@ -17,3 +17,12 @@ two:
|
||||
max_usages: 10
|
||||
active: true
|
||||
validity_per_user: always
|
||||
|
||||
cash:
|
||||
name: Cash Code
|
||||
code: ZERG6H1R65H
|
||||
amount_off: 10000
|
||||
valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||
max_usages: 1
|
||||
active: true
|
||||
validity_per_user: once
|
12
test/fixtures/event_price_categories.yml
vendored
12
test/fixtures/event_price_categories.yml
vendored
@ -11,3 +11,15 @@ two:
|
||||
event_id: 2
|
||||
price_category_id: 1
|
||||
amount: 1700
|
||||
|
||||
radio_youngs:
|
||||
id: 3
|
||||
event_id: 4
|
||||
price_category_id: 1
|
||||
amount: 7500
|
||||
|
||||
radio_unemployed:
|
||||
id: 4
|
||||
event_id: 4
|
||||
price_category_id: 2
|
||||
amount: 8000
|
13
test/fixtures/events.yml
vendored
13
test/fixtures/events.yml
vendored
@ -41,3 +41,16 @@ event_1:
|
||||
nb_free_places: 10
|
||||
recurrence_id: 1
|
||||
category_id: 2
|
||||
|
||||
event_4:
|
||||
id: 4
|
||||
title: Radio numérique
|
||||
description: "Confectionnez votre propre récepteur FM compatible avec la radio numérique terrestre (RNT) :\r\n- logiciel
|
||||
embarqué\r\n- électronique\r\n- démodulation d'ondes porteuses\r\n- conception et réalisation du design"
|
||||
created_at: 2016-11-28 10:52:50.615611000 Z
|
||||
updated_at: 2016-11-28 10:52:50.615611000 Z
|
||||
availability_id: 17
|
||||
amount: 10000
|
||||
nb_total_places: 10
|
||||
nb_free_places: 10
|
||||
category_id: 1
|
@ -3,7 +3,7 @@ class AdminsTest < ActionDispatch::IntegrationTest
|
||||
# Called before every test method runs. Can be used
|
||||
# to set up fixture information.
|
||||
def setup
|
||||
@admin = User.find_by_username('admin')
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
|
@ -20,7 +20,7 @@ module Availabilities
|
||||
end
|
||||
|
||||
test 'get machine availabilities as admin' do
|
||||
m = Machine.find_by_slug('decoupeuse-vinyle')
|
||||
m = Machine.find_by(slug: 'decoupeuse-vinyle')
|
||||
|
||||
get "/api/availabilities/machines/#{m.id}"
|
||||
|
||||
|
@ -1,11 +1,11 @@
|
||||
class Availabilities::AsUserTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
user = User.find_by_username('kdumas')
|
||||
user = User.find_by(username: 'kdumas')
|
||||
login_as(user, scope: :user)
|
||||
end
|
||||
|
||||
test 'get machine availabilities as user' do
|
||||
m = Machine.find_by_slug('decoupeuse-vinyle')
|
||||
m = Machine.find_by(slug: 'decoupeuse-vinyle')
|
||||
|
||||
get "/api/availabilities/machines/#{m.id}"
|
||||
|
||||
|
206
test/integration/events/as_admin_test.rb
Normal file
206
test/integration/events/as_admin_test.rb
Normal file
@ -0,0 +1,206 @@
|
||||
module Events
|
||||
class AsAdminTest < ActionDispatch::IntegrationTest
|
||||
|
||||
setup do
|
||||
admin = User.with_role(:admin).first
|
||||
login_as(admin, scope: :user)
|
||||
end
|
||||
|
||||
test 'creation modification reservation and re-modification scenario' do
|
||||
|
||||
# First, we create a new event
|
||||
post '/api/events',
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the event was created correctly
|
||||
event = json_response(response.body)
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_not_nil e, 'Event was not created in database'
|
||||
|
||||
# Check the remaining free places are not defined
|
||||
assert_nil e.nb_free_places, "Free places shouldn't be defined"
|
||||
|
||||
# Then, modify the event to set a nb of places
|
||||
put "/api/events/#{e.id}",
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 10
|
||||
}
|
||||
}
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 200, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the places numbers were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 10, e.nb_total_places, 'Total number of places was not updated'
|
||||
assert_equal 10, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Now, let's make a reservation on this event
|
||||
post '/api/reservations',
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'pdurand').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 2,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the remaining places were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 8, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Finally, modify the event to add some places
|
||||
put "/api/events/#{e.id}",
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 20
|
||||
}
|
||||
}
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 200, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the places numbers were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
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
|
||||
|
||||
test 'create event with custom price and reserve it with success' do
|
||||
|
||||
price_category = PriceCategory.first
|
||||
|
||||
# First, we create a new event
|
||||
post '/api/events',
|
||||
{
|
||||
event: {
|
||||
title: 'Electronics initiation',
|
||||
description: 'A workshop about electronics and the abilities to create robots.',
|
||||
start_date: 1.week.from_now.utc + 2.days,
|
||||
start_time: 1.week.from_now.utc.change({hour: 18}) + 2.days,
|
||||
end_date: 1.week.from_now.utc + 2.days,
|
||||
end_time: 1.week.from_now.utc.change({hour: 22}) + 2.days,
|
||||
category_id: Category.last.id,
|
||||
amount: 20,
|
||||
nb_total_places: 10,
|
||||
event_price_categories_attributes: [
|
||||
{
|
||||
price_category_id: price_category.id.to_s,
|
||||
amount: 16.to_s
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the event was created correctly
|
||||
event = json_response(response.body)
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_not_nil e, 'Event was not created in database'
|
||||
|
||||
# Check the places numbers were set successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 10, e.nb_total_places, 'Total number of places was not updated'
|
||||
assert_equal 10, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Now, let's make a reservation on this event
|
||||
post '/api/reservations',
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'lseguin').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 4,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
],
|
||||
tickets_attributes: [
|
||||
{
|
||||
event_price_category_id: e.event_price_categories.first.id,
|
||||
booked: 4
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the reservation match the required event
|
||||
reservation = json_response(response.body)
|
||||
r = Reservation.find(reservation[:id])
|
||||
|
||||
assert_equal e.id, r.reservable_id
|
||||
assert_equal 'Event', r.reservable_type
|
||||
|
||||
# Check the remaining places were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 2, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Check the resulting invoice generation and it has right price
|
||||
assert_invoice_pdf r.invoice
|
||||
assert_equal (4 * 20) + (4 * 16), r.invoice.total / 100.0
|
||||
|
||||
end
|
||||
end
|
||||
end
|
103
test/integration/events/as_user_test.rb
Normal file
103
test/integration/events/as_user_test.rb
Normal file
@ -0,0 +1,103 @@
|
||||
module Events
|
||||
class AsUserTest < ActionDispatch::IntegrationTest
|
||||
|
||||
test 'reserve event with many prices and payment means' do
|
||||
|
||||
vlonchamp = User.find_by(username: 'vlonchamp')
|
||||
login_as(vlonchamp, scope: :user)
|
||||
|
||||
radio = Event.find(4)
|
||||
availability = radio.availability
|
||||
|
||||
reservations_count = Reservation.count
|
||||
invoice_count = Invoice.count
|
||||
invoice_items_count = InvoiceItem.count
|
||||
users_credit_count = UsersCredit.count
|
||||
wallet_transactions_count = WalletTransaction.count
|
||||
|
||||
# Reserve the 'radio' event
|
||||
VCR.use_cassette('reserve_event_with_many_prices_and_payment_means') do
|
||||
post reservations_path, {
|
||||
reservation: {
|
||||
user_id: User.find_by(username: 'vlonchamp').id,
|
||||
reservable_id: radio.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 2,
|
||||
card_token: stripe_card_token,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: availability.start_at,
|
||||
end_at: availability.end_at,
|
||||
availability_id: availability.id,
|
||||
offered: false
|
||||
}
|
||||
],
|
||||
tickets_attributes: [
|
||||
{
|
||||
event_price_category_id: radio.event_price_categories[0].id,
|
||||
booked: 2
|
||||
},
|
||||
{
|
||||
event_price_category_id: radio.event_price_categories[1].id,
|
||||
booked: 2
|
||||
}
|
||||
]
|
||||
},
|
||||
coupon_code: 'SUNNYFABLAB'
|
||||
}.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?
|
||||
assert_equal 43350, invoice.total
|
||||
|
||||
# invoice_items assertions
|
||||
## reservation
|
||||
reservation_item = invoice.invoice_items.first
|
||||
|
||||
assert_not_nil reservation_item
|
||||
assert reservation_item.stp_invoice_item_id
|
||||
assert_equal 51000, reservation_item.amount
|
||||
|
||||
# invoice assertions
|
||||
invoice = Invoice.find_by(invoiced: reservation)
|
||||
assert_invoice_pdf invoice
|
||||
|
||||
VCR.use_cassette('reserve_event_with_many_prices_and_payment_means_retrieve_invoice_from_stripe') do
|
||||
stp_invoice = Stripe::Invoice.retrieve(invoice.stp_invoice_id)
|
||||
assert_equal stp_invoice.total, (invoice.total - invoice.wallet_amount)
|
||||
end
|
||||
|
||||
# wallet assertions
|
||||
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
|
||||
|
||||
# notifications
|
||||
assert_not_empty Notification.where(attached_object: reservation)
|
||||
assert_not_empty Notification.where(attached_object: invoice)
|
||||
|
||||
end
|
||||
end
|
||||
end
|
@ -1,204 +0,0 @@
|
||||
class EventsTest < ActionDispatch::IntegrationTest
|
||||
|
||||
setup do
|
||||
admin = User.with_role(:admin).first
|
||||
login_as(admin, scope: :user)
|
||||
end
|
||||
|
||||
test 'creation modification reservation and re-modification scenario' do
|
||||
|
||||
# First, we create a new event
|
||||
post '/api/events',
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the event was created correctly
|
||||
event = json_response(response.body)
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_not_nil e, 'Event was not created in database'
|
||||
|
||||
# Check the remaining free places are not defined
|
||||
assert_nil e.nb_free_places, "Free places shouldn't be defined"
|
||||
|
||||
# Then, modify the event to set a nb of places
|
||||
put "/api/events/#{e.id}",
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 10
|
||||
}
|
||||
}
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 200, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the places numbers were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 10, e.nb_total_places, 'Total number of places was not updated'
|
||||
assert_equal 10, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Now, let's make a reservation on this event
|
||||
post '/api/reservations',
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by_username('pdurand').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 2,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the remaining places were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 8, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Finally, modify the event to add some places
|
||||
put "/api/events/#{e.id}",
|
||||
{
|
||||
event: {
|
||||
title: 'OpenLab discovery day',
|
||||
description: 'A day to discover the Fablab and try its machines and possibilities.',
|
||||
start_date: 1.week.from_now.utc,
|
||||
start_time: 1.week.from_now.utc.change({hour: 16}),
|
||||
end_date: 1.week.from_now.utc,
|
||||
end_time: 1.week.from_now.utc.change({hour: 20}),
|
||||
category_id: Category.first.id,
|
||||
amount: 0,
|
||||
nb_total_places: 20
|
||||
}
|
||||
}
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 200, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the places numbers were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
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
|
||||
|
||||
test 'create event with custom price and reserve it with success' do
|
||||
|
||||
price_category = PriceCategory.first
|
||||
|
||||
# First, we create a new event
|
||||
post '/api/events',
|
||||
{
|
||||
event: {
|
||||
title: 'Electronics initiation',
|
||||
description: 'A workshop about electronics and the abilities to create robots.',
|
||||
start_date: 1.week.from_now.utc + 2.days,
|
||||
start_time: 1.week.from_now.utc.change({hour: 18}) + 2.days,
|
||||
end_date: 1.week.from_now.utc + 2.days,
|
||||
end_time: 1.week.from_now.utc.change({hour: 22}) + 2.days,
|
||||
category_id: Category.last.id,
|
||||
amount: 20,
|
||||
nb_total_places: 10,
|
||||
event_price_categories_attributes: [
|
||||
{
|
||||
price_category_id: price_category.id.to_s,
|
||||
amount: 16.to_s
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the event was created correctly
|
||||
event = json_response(response.body)
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_not_nil e, 'Event was not created in database'
|
||||
|
||||
# Check the places numbers were set successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 10, e.nb_total_places, 'Total number of places was not updated'
|
||||
assert_equal 10, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Now, let's make a reservation on this event
|
||||
post '/api/reservations',
|
||||
{
|
||||
reservation: {
|
||||
user_id: User.find_by_username('lseguin').id,
|
||||
reservable_id: e.id,
|
||||
reservable_type: 'Event',
|
||||
nb_reserve_places: 4,
|
||||
slots_attributes: [
|
||||
{
|
||||
start_at: e.availability.start_at,
|
||||
end_at: e.availability.end_at,
|
||||
availability_id: e.availability.id,
|
||||
offered: false
|
||||
}
|
||||
],
|
||||
tickets_attributes: [
|
||||
{
|
||||
event_price_category_id: e.event_price_categories.first.id,
|
||||
booked: 4
|
||||
}
|
||||
]
|
||||
}
|
||||
}.to_json,
|
||||
default_headers
|
||||
|
||||
# Check response format & status
|
||||
assert_equal 201, response.status, response.body
|
||||
assert_equal Mime::JSON, response.content_type
|
||||
|
||||
# Check the reservation match the required event
|
||||
reservation = json_response(response.body)
|
||||
r = Reservation.find(reservation[:id])
|
||||
|
||||
assert_equal e.id, r.reservable_id
|
||||
assert_equal 'Event', r.reservable_type
|
||||
|
||||
# Check the remaining places were updated successfully
|
||||
e = Event.where(id: event[:id]).first
|
||||
assert_equal 2, e.nb_free_places, 'Number of free places was not updated'
|
||||
|
||||
# Check the resulting invoice generation and it has right price
|
||||
assert_invoice_pdf r.invoice
|
||||
assert_equal (4 * 20) + (4 * 16), r.invoice.total / 100.0
|
||||
|
||||
end
|
||||
end
|
@ -3,12 +3,12 @@ module Subscriptions
|
||||
|
||||
|
||||
setup do
|
||||
@admin = User.find_by_username('admin')
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
test "admin successfully takes a subscription for a user" do
|
||||
user = User.find_by_username('jdupond')
|
||||
user = User.find_by(username: 'jdupond')
|
||||
plan = Plan.find_by(group_id: user.group.id, type: 'Plan', base_name: 'Mensuel')
|
||||
|
||||
VCR.use_cassette("subscriptions_admin_create_success") do
|
||||
@ -40,7 +40,7 @@ module Subscriptions
|
||||
assert_equal user.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')
|
||||
printer = Machine.find_by(slug: 'imprimante-3d')
|
||||
assert_equal 15, (printer.prices.find_by(group_id: user.group_id, plan_id: user.subscription.plan_id).amount / 100), 'machine hourly price does not match'
|
||||
|
||||
# Check notification was sent to the user
|
||||
|
@ -2,7 +2,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
|
||||
|
||||
|
||||
setup do
|
||||
@user = User.find_by_username('jdupond')
|
||||
@user = User.find_by(username: 'jdupond')
|
||||
login_as(@user, scope: :user)
|
||||
end
|
||||
|
||||
@ -38,7 +38,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
|
||||
assert_equal @user.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')
|
||||
printer = Machine.find_by(slug: 'imprimante-3d')
|
||||
assert_equal 15, (printer.prices.find_by(group_id: @user.group_id, plan_id: @user.subscription.plan_id).amount / 100), 'machine hourly price does not match'
|
||||
|
||||
# Check notifications were sent for every admins
|
||||
@ -118,7 +118,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
|
||||
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')
|
||||
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
|
||||
|
@ -1,13 +1,13 @@
|
||||
class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest
|
||||
|
||||
setup do
|
||||
@admin = User.find_by_username('admin')
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
end
|
||||
|
||||
test 'admin successfully renew a subscription before it has ended' do
|
||||
|
||||
user = User.find_by_username('kdumas')
|
||||
user = User.find_by(username: 'kdumas')
|
||||
plan = Plan.find_by(base_name: 'Mensuel tarif réduit')
|
||||
|
||||
VCR.use_cassette("subscriptions_admin_renew_success") do
|
||||
@ -38,7 +38,7 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest
|
||||
assert_equal user.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')
|
||||
printer = Machine.find_by(slug: 'imprimante-3d')
|
||||
assert_equal 10, (printer.prices.find_by(group_id: user.group_id, plan_id: user.subscription.plan_id).amount / 100), 'machine hourly price does not match'
|
||||
|
||||
# Check notification was sent to the user
|
||||
|
@ -2,7 +2,7 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest
|
||||
|
||||
|
||||
setup do
|
||||
@user = User.find_by_username('lseguin')
|
||||
@user = User.find_by(username: 'lseguin')
|
||||
login_as(@user, scope: :user)
|
||||
end
|
||||
|
||||
|
@ -24,7 +24,7 @@ class WalletsTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
test 'admin can get wallet by user id' do
|
||||
@admin = User.find_by_username('admin')
|
||||
@admin = User.find_by(username: 'admin')
|
||||
login_as(@admin, scope: :user)
|
||||
@user1 = User.first
|
||||
get "/api/wallet/by_user/#{@user1.id}"
|
||||
|
@ -7,12 +7,22 @@ class CouponTest < ActiveSupport::TestCase
|
||||
end
|
||||
|
||||
test 'expired coupon must return the proper status' do
|
||||
c = Coupon.find_by_code('XMAS10')
|
||||
assert c.status == 'expired'
|
||||
c = Coupon.find_by(code: 'XMAS10')
|
||||
assert_equal 'expired', c.status
|
||||
end
|
||||
|
||||
test 'two coupons cannot have the same code' do
|
||||
c = Coupon.new({name: 'Summer deals', code: 'SUNNYFABLAB', percent_off: 15, validity_per_user: 'always'})
|
||||
assert c.invalid?
|
||||
end
|
||||
|
||||
test 'coupon with cash amount has amount_off type' do
|
||||
c = Coupon.new({name: 'Essential Box', code: 'KWXX2M', amount_off: 2000, validity_per_user: 'once', max_usages: 1})
|
||||
assert_equal 'amount_off', c.type
|
||||
end
|
||||
|
||||
test 'coupon with cash amount cannot be used with cheaper cart' do
|
||||
c = Coupon.new({name: 'Premium Box', code: '6DDX2T44MQ', amount_off: 20000, validity_per_user: 'once', max_usages: 1, active: true})
|
||||
assert_equal 'amount_exceeded', c.status(User.find_by(username: 'jdupond').id, 2000)
|
||||
end
|
||||
end
|
||||
|
28
test/services/coupon_apply_service_test.rb
Normal file
28
test/services/coupon_apply_service_test.rb
Normal file
@ -0,0 +1,28 @@
|
||||
require 'test_helper'
|
||||
|
||||
class CouponApplyServiceTest < ActiveSupport::TestCase
|
||||
setup do
|
||||
@jdupond = User.find_by(username: 'jdupond')
|
||||
@cash_coupon = Coupon.find_by(code: 'ZERG6H1R65H')
|
||||
end
|
||||
|
||||
test 'user apply percent coupon to cart' do
|
||||
total = CouponApplyService.new.(1000, 'SUNNYFABLAB', @jdupond.id)
|
||||
assert_equal 850, total
|
||||
end
|
||||
|
||||
test 'user cannot apply excessive coupon to cart' do
|
||||
total = CouponApplyService.new.(1000, @cash_coupon, @jdupond.id)
|
||||
assert_equal 1000, total
|
||||
end
|
||||
|
||||
test 'user cannot apply invalid coupon to cart' do
|
||||
total = CouponApplyService.new.(1000, 'INVALIDCODE', @jdupond.id)
|
||||
assert_equal 1000, total
|
||||
end
|
||||
|
||||
test 'user cannot apply expired coupon to cart' do
|
||||
total = CouponApplyService.new.(1000, 'XMAS10', @jdupond.id)
|
||||
assert_equal 1000, total
|
||||
end
|
||||
end
|
@ -0,0 +1,954 @@
|
||||
---
|
||||
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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '81'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:21 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '779'
|
||||
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_9e4YKniSPeMq2N
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |
|
||||
{
|
||||
"id": "tok_19KmOv2sOmf47Nz90KKaBGgJ",
|
||||
"object": "token",
|
||||
"card": {
|
||||
"id": "card_19KmOv2sOmf47Nz94YYaGGHa",
|
||||
"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.237.73",
|
||||
"created": 1480329021,
|
||||
"livemode": false,
|
||||
"type": "card",
|
||||
"used": false
|
||||
}
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:21 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/invoiceitems
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: customer=cus_8CzNtM08NVlSGN&amount=51000¤cy=usd&description=Radio+num%C3%A9rique+%0ADecember+08%2C+2016+11%3A00+AM+-+07%3A00+PM%0ADecember+09%2C+2016+11%3A00+AM+-+07%3A00+PM%0ADecember+10%2C+2016+11%3A00+AM+-+07%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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '225'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:22 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '552'
|
||||
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_9e4Y3qKoP2Yqmq
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: ASCII-8BIT
|
||||
string: !binary |-
|
||||
ewogICJpZCI6ICJpaV8xOUttT3cyc09tZjQ3Tno5ZjBQYktiSHEiLAogICJv
|
||||
YmplY3QiOiAiaW52b2ljZWl0ZW0iLAogICJhbW91bnQiOiA1MTAwMCwKICAi
|
||||
Y3VycmVuY3kiOiAidXNkIiwKICAiY3VzdG9tZXIiOiAiY3VzXzhDek50TTA4
|
||||
TlZsU0dOIiwKICAiZGF0ZSI6IDE0ODAzMjkwMjIsCiAgImRlc2NyaXB0aW9u
|
||||
IjogIlJhZGlvIG51bcOpcmlxdWUgXG5EZWNlbWJlciAwOCwgMjAxNiAxMTow
|
||||
MCBBTSAtIDA3OjAwIFBNXG5EZWNlbWJlciAwOSwgMjAxNiAxMTowMCBBTSAt
|
||||
IDA3OjAwIFBNXG5EZWNlbWJlciAxMCwgMjAxNiAxMTowMCBBTSAtIDA3OjAw
|
||||
IFBNIiwKICAiZGlzY291bnRhYmxlIjogdHJ1ZSwKICAiaW52b2ljZSI6IG51
|
||||
bGwsCiAgImxpdmVtb2RlIjogZmFsc2UsCiAgIm1ldGFkYXRhIjoge30sCiAg
|
||||
InBlcmlvZCI6IHsKICAgICJzdGFydCI6IDE0ODAzMjkwMjIsCiAgICAiZW5k
|
||||
IjogMTQ4MDMyOTAyMgogIH0sCiAgInBsYW4iOiBudWxsLAogICJwcm9yYXRp
|
||||
b24iOiBmYWxzZSwKICAicXVhbnRpdHkiOiBudWxsLAogICJzdWJzY3JpcHRp
|
||||
b24iOiBudWxsCn0K
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:22 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/invoiceitems
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: customer=cus_8CzNtM08NVlSGN&amount=-7650¤cy=usd&description=coupon+SUNNYFABLAB+-+reservation
|
||||
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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '98'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:23 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '451'
|
||||
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_9e4YzTw5ITNQ7t
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |
|
||||
{
|
||||
"id": "ii_19KmOw2sOmf47Nz9fMgjHIhg",
|
||||
"object": "invoiceitem",
|
||||
"amount": -7650,
|
||||
"currency": "usd",
|
||||
"customer": "cus_8CzNtM08NVlSGN",
|
||||
"date": 1480329022,
|
||||
"description": "coupon SUNNYFABLAB - reservation",
|
||||
"discountable": false,
|
||||
"invoice": null,
|
||||
"livemode": false,
|
||||
"metadata": {},
|
||||
"period": {
|
||||
"start": 1480329022,
|
||||
"end": 1480329022
|
||||
},
|
||||
"plan": null,
|
||||
"proration": false,
|
||||
"quantity": null,
|
||||
"subscription": null
|
||||
}
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:23 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/invoiceitems
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: customer=cus_8CzNtM08NVlSGN&amount=-1000¤cy=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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '78'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:23 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_9e4YHcxKC6TIpx
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |
|
||||
{
|
||||
"id": "ii_19KmOx2sOmf47Nz9XIzvTjLC",
|
||||
"object": "invoiceitem",
|
||||
"amount": -1000,
|
||||
"currency": "usd",
|
||||
"customer": "cus_8CzNtM08NVlSGN",
|
||||
"date": 1480329023,
|
||||
"description": "wallet -10.0",
|
||||
"discountable": false,
|
||||
"invoice": null,
|
||||
"livemode": false,
|
||||
"metadata": {},
|
||||
"period": {
|
||||
"start": 1480329023,
|
||||
"end": 1480329023
|
||||
},
|
||||
"plan": null,
|
||||
"proration": false,
|
||||
"quantity": null,
|
||||
"subscription": null
|
||||
}
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:23 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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:24 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '1415'
|
||||
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_9e4YUv3IAopxIK
|
||||
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": "usd",
|
||||
"default_source": "card_18ZhUf2sOmf47Nz9LhkQeEmO",
|
||||
"delinquent": false,
|
||||
"description": "Vanessa Lonchamp",
|
||||
"discount": null,
|
||||
"email": "vanessa.lonchamp@sfr.fr",
|
||||
"livemode": false,
|
||||
"metadata": {},
|
||||
"shipping": null,
|
||||
"sources": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"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",
|
||||
"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": [],
|
||||
"has_more": false,
|
||||
"total_count": 0,
|
||||
"url": "/v1/customers/cus_8CzNtM08NVlSGN/subscriptions"
|
||||
}
|
||||
}
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:24 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/sources
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: card=tok_19KmOv2sOmf47Nz90KKaBGgJ
|
||||
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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '33'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:25 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_9e4Ychb7UhSBol
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |
|
||||
{
|
||||
"id": "card_19KmOv2sOmf47Nz94YYaGGHa",
|
||||
"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: Mon, 28 Nov 2016 10:30:25 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: default_source=card_19KmOv2sOmf47Nz94YYaGGHa
|
||||
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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '44'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:26 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '2143'
|
||||
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_9e4Y7M4v5B4FLQ
|
||||
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": "usd",
|
||||
"default_source": "card_19KmOv2sOmf47Nz94YYaGGHa",
|
||||
"delinquent": false,
|
||||
"description": "Vanessa Lonchamp",
|
||||
"discount": null,
|
||||
"email": "vanessa.lonchamp@sfr.fr",
|
||||
"livemode": false,
|
||||
"metadata": {},
|
||||
"shipping": null,
|
||||
"sources": {
|
||||
"object": "list",
|
||||
"data": [
|
||||
{
|
||||
"id": "card_19KmOv2sOmf47Nz94YYaGGHa",
|
||||
"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_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",
|
||||
"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": [],
|
||||
"has_more": false,
|
||||
"total_count": 0,
|
||||
"url": "/v1/customers/cus_8CzNtM08NVlSGN/subscriptions"
|
||||
}
|
||||
}
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:26 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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '27'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:27 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '2516'
|
||||
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_9e4YqC96ZArjnb
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: ASCII-8BIT
|
||||
string: !binary |-
|
||||
ewogICJpZCI6ICJpbl8xOUttUDEyc09tZjQ3Tno5Umw2YUtXRjgiLAogICJv
|
||||
YmplY3QiOiAiaW52b2ljZSIsCiAgImFtb3VudF9kdWUiOiA0MjM1MCwKICAi
|
||||
YXBwbGljYXRpb25fZmVlIjogbnVsbCwKICAiYXR0ZW1wdF9jb3VudCI6IDAs
|
||||
CiAgImF0dGVtcHRlZCI6IGZhbHNlLAogICJjaGFyZ2UiOiBudWxsLAogICJj
|
||||
bG9zZWQiOiBmYWxzZSwKICAiY3VycmVuY3kiOiAidXNkIiwKICAiY3VzdG9t
|
||||
ZXIiOiAiY3VzXzhDek50TTA4TlZsU0dOIiwKICAiZGF0ZSI6IDE0ODAzMjkw
|
||||
MjcsCiAgImRlc2NyaXB0aW9uIjogbnVsbCwKICAiZGlzY291bnQiOiBudWxs
|
||||
LAogICJlbmRpbmdfYmFsYW5jZSI6IG51bGwsCiAgImZvcmdpdmVuIjogZmFs
|
||||
c2UsCiAgImxpbmVzIjogewogICAgIm9iamVjdCI6ICJsaXN0IiwKICAgICJk
|
||||
YXRhIjogWwogICAgICB7CiAgICAgICAgImlkIjogImlpXzE5S21PeDJzT21m
|
||||
NDdOejlYSXp2VGpMQyIsCiAgICAgICAgIm9iamVjdCI6ICJsaW5lX2l0ZW0i
|
||||
LAogICAgICAgICJhbW91bnQiOiAtMTAwMCwKICAgICAgICAiY3VycmVuY3ki
|
||||
OiAidXNkIiwKICAgICAgICAiZGVzY3JpcHRpb24iOiAid2FsbGV0IC0xMC4w
|
||||
IiwKICAgICAgICAiZGlzY291bnRhYmxlIjogZmFsc2UsCiAgICAgICAgImxp
|
||||
dmVtb2RlIjogZmFsc2UsCiAgICAgICAgIm1ldGFkYXRhIjoge30sCiAgICAg
|
||||
ICAgInBlcmlvZCI6IHsKICAgICAgICAgICJzdGFydCI6IDE0ODAzMjkwMjMs
|
||||
CiAgICAgICAgICAiZW5kIjogMTQ4MDMyOTAyMwogICAgICAgIH0sCiAgICAg
|
||||
ICAgInBsYW4iOiBudWxsLAogICAgICAgICJwcm9yYXRpb24iOiBmYWxzZSwK
|
||||
ICAgICAgICAicXVhbnRpdHkiOiBudWxsLAogICAgICAgICJzdWJzY3JpcHRp
|
||||
b24iOiBudWxsLAogICAgICAgICJ0eXBlIjogImludm9pY2VpdGVtIgogICAg
|
||||
ICB9LAogICAgICB7CiAgICAgICAgImlkIjogImlpXzE5S21PdzJzT21mNDdO
|
||||
ejlmTWdqSEloZyIsCiAgICAgICAgIm9iamVjdCI6ICJsaW5lX2l0ZW0iLAog
|
||||
ICAgICAgICJhbW91bnQiOiAtNzY1MCwKICAgICAgICAiY3VycmVuY3kiOiAi
|
||||
dXNkIiwKICAgICAgICAiZGVzY3JpcHRpb24iOiAiY291cG9uIFNVTk5ZRkFC
|
||||
TEFCIC0gcmVzZXJ2YXRpb24iLAogICAgICAgICJkaXNjb3VudGFibGUiOiBm
|
||||
YWxzZSwKICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAibWV0
|
||||
YWRhdGEiOiB7fSwKICAgICAgICAicGVyaW9kIjogewogICAgICAgICAgInN0
|
||||
YXJ0IjogMTQ4MDMyOTAyMiwKICAgICAgICAgICJlbmQiOiAxNDgwMzI5MDIy
|
||||
CiAgICAgICAgfSwKICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAgInBy
|
||||
b3JhdGlvbiI6IGZhbHNlLAogICAgICAgICJxdWFudGl0eSI6IG51bGwsCiAg
|
||||
ICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgInR5cGUiOiAi
|
||||
aW52b2ljZWl0ZW0iCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiaWQiOiAi
|
||||
aWlfMTlLbU93MnNPbWY0N056OWYwUGJLYkhxIiwKICAgICAgICAib2JqZWN0
|
||||
IjogImxpbmVfaXRlbSIsCiAgICAgICAgImFtb3VudCI6IDUxMDAwLAogICAg
|
||||
ICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICJkZXNjcmlwdGlvbiI6
|
||||
ICJSYWRpbyBudW3DqXJpcXVlIFxuRGVjZW1iZXIgMDgsIDIwMTYgMTE6MDAg
|
||||
QU0gLSAwNzowMCBQTVxuRGVjZW1iZXIgMDksIDIwMTYgMTE6MDAgQU0gLSAw
|
||||
NzowMCBQTVxuRGVjZW1iZXIgMTAsIDIwMTYgMTE6MDAgQU0gLSAwNzowMCBQ
|
||||
TSIsCiAgICAgICAgImRpc2NvdW50YWJsZSI6IHRydWUsCiAgICAgICAgImxp
|
||||
dmVtb2RlIjogZmFsc2UsCiAgICAgICAgIm1ldGFkYXRhIjoge30sCiAgICAg
|
||||
ICAgInBlcmlvZCI6IHsKICAgICAgICAgICJzdGFydCI6IDE0ODAzMjkwMjIs
|
||||
CiAgICAgICAgICAiZW5kIjogMTQ4MDMyOTAyMgogICAgICAgIH0sCiAgICAg
|
||||
ICAgInBsYW4iOiBudWxsLAogICAgICAgICJwcm9yYXRpb24iOiBmYWxzZSwK
|
||||
ICAgICAgICAicXVhbnRpdHkiOiBudWxsLAogICAgICAgICJzdWJzY3JpcHRp
|
||||
b24iOiBudWxsLAogICAgICAgICJ0eXBlIjogImludm9pY2VpdGVtIgogICAg
|
||||
ICB9CiAgICBdLAogICAgImhhc19tb3JlIjogZmFsc2UsCiAgICAidG90YWxf
|
||||
Y291bnQiOiAzLAogICAgInVybCI6ICIvdjEvaW52b2ljZXMvaW5fMTlLbVAx
|
||||
MnNPbWY0N056OVJsNmFLV0Y4L2xpbmVzIgogIH0sCiAgImxpdmVtb2RlIjog
|
||||
ZmFsc2UsCiAgIm1ldGFkYXRhIjoge30sCiAgIm5leHRfcGF5bWVudF9hdHRl
|
||||
bXB0IjogMTQ4MDMzMjYyNywKICAicGFpZCI6IGZhbHNlLAogICJwZXJpb2Rf
|
||||
ZW5kIjogMTQ4MDMyOTAyNywKICAicGVyaW9kX3N0YXJ0IjogMTQ4MDMyOTAy
|
||||
NywKICAicmVjZWlwdF9udW1iZXIiOiBudWxsLAogICJzdGFydGluZ19iYWxh
|
||||
bmNlIjogMCwKICAic3RhdGVtZW50X2Rlc2NyaXB0b3IiOiBudWxsLAogICJz
|
||||
dWJzY3JpcHRpb24iOiBudWxsLAogICJzdWJ0b3RhbCI6IDQyMzUwLAogICJ0
|
||||
YXgiOiBudWxsLAogICJ0YXhfcGVyY2VudCI6IG51bGwsCiAgInRvdGFsIjog
|
||||
NDIzNTAsCiAgIndlYmhvb2tzX2RlbGl2ZXJlZF9hdCI6IG51bGwKfQo=
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:27 GMT
|
||||
- request:
|
||||
method: post
|
||||
uri: https://api.stripe.com/v1/invoices/in_19KmP12sOmf47Nz9Rl6aKWF8/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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
Content-Length:
|
||||
- '0'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:28 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '2535'
|
||||
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_9e4Y7QI51Jw753
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: ASCII-8BIT
|
||||
string: !binary |-
|
||||
ewogICJpZCI6ICJpbl8xOUttUDEyc09tZjQ3Tno5Umw2YUtXRjgiLAogICJv
|
||||
YmplY3QiOiAiaW52b2ljZSIsCiAgImFtb3VudF9kdWUiOiA0MjM1MCwKICAi
|
||||
YXBwbGljYXRpb25fZmVlIjogbnVsbCwKICAiYXR0ZW1wdF9jb3VudCI6IDEs
|
||||
CiAgImF0dGVtcHRlZCI6IHRydWUsCiAgImNoYXJnZSI6ICJjaF8xOUttUDIy
|
||||
c09tZjQ3Tno5M2lmYklVMmkiLAogICJjbG9zZWQiOiB0cnVlLAogICJjdXJy
|
||||
ZW5jeSI6ICJ1c2QiLAogICJjdXN0b21lciI6ICJjdXNfOEN6TnRNMDhOVmxT
|
||||
R04iLAogICJkYXRlIjogMTQ4MDMyOTAyNywKICAiZGVzY3JpcHRpb24iOiBu
|
||||
dWxsLAogICJkaXNjb3VudCI6IG51bGwsCiAgImVuZGluZ19iYWxhbmNlIjog
|
||||
MCwKICAiZm9yZ2l2ZW4iOiBmYWxzZSwKICAibGluZXMiOiB7CiAgICAib2Jq
|
||||
ZWN0IjogImxpc3QiLAogICAgImRhdGEiOiBbCiAgICAgIHsKICAgICAgICAi
|
||||
aWQiOiAiaWlfMTlLbU94MnNPbWY0N056OVhJenZUakxDIiwKICAgICAgICAi
|
||||
b2JqZWN0IjogImxpbmVfaXRlbSIsCiAgICAgICAgImFtb3VudCI6IC0xMDAw
|
||||
LAogICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICJkZXNjcmlw
|
||||
dGlvbiI6ICJ3YWxsZXQgLTEwLjAiLAogICAgICAgICJkaXNjb3VudGFibGUi
|
||||
OiBmYWxzZSwKICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAi
|
||||
bWV0YWRhdGEiOiB7fSwKICAgICAgICAicGVyaW9kIjogewogICAgICAgICAg
|
||||
InN0YXJ0IjogMTQ4MDMyOTAyMywKICAgICAgICAgICJlbmQiOiAxNDgwMzI5
|
||||
MDIzCiAgICAgICAgfSwKICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAg
|
||||
InByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICJxdWFudGl0eSI6IG51bGws
|
||||
CiAgICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgInR5cGUi
|
||||
OiAiaW52b2ljZWl0ZW0iCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiaWQi
|
||||
OiAiaWlfMTlLbU93MnNPbWY0N056OWZNZ2pISWhnIiwKICAgICAgICAib2Jq
|
||||
ZWN0IjogImxpbmVfaXRlbSIsCiAgICAgICAgImFtb3VudCI6IC03NjUwLAog
|
||||
ICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICJkZXNjcmlwdGlv
|
||||
biI6ICJjb3Vwb24gU1VOTllGQUJMQUIgLSByZXNlcnZhdGlvbiIsCiAgICAg
|
||||
ICAgImRpc2NvdW50YWJsZSI6IGZhbHNlLAogICAgICAgICJsaXZlbW9kZSI6
|
||||
IGZhbHNlLAogICAgICAgICJtZXRhZGF0YSI6IHt9LAogICAgICAgICJwZXJp
|
||||
b2QiOiB7CiAgICAgICAgICAic3RhcnQiOiAxNDgwMzI5MDIyLAogICAgICAg
|
||||
ICAgImVuZCI6IDE0ODAzMjkwMjIKICAgICAgICB9LAogICAgICAgICJwbGFu
|
||||
IjogbnVsbCwKICAgICAgICAicHJvcmF0aW9uIjogZmFsc2UsCiAgICAgICAg
|
||||
InF1YW50aXR5IjogbnVsbCwKICAgICAgICAic3Vic2NyaXB0aW9uIjogbnVs
|
||||
bCwKICAgICAgICAidHlwZSI6ICJpbnZvaWNlaXRlbSIKICAgICAgfSwKICAg
|
||||
ICAgewogICAgICAgICJpZCI6ICJpaV8xOUttT3cyc09tZjQ3Tno5ZjBQYkti
|
||||
SHEiLAogICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAi
|
||||
YW1vdW50IjogNTEwMDAsCiAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAg
|
||||
ICAgICAgImRlc2NyaXB0aW9uIjogIlJhZGlvIG51bcOpcmlxdWUgXG5EZWNl
|
||||
bWJlciAwOCwgMjAxNiAxMTowMCBBTSAtIDA3OjAwIFBNXG5EZWNlbWJlciAw
|
||||
OSwgMjAxNiAxMTowMCBBTSAtIDA3OjAwIFBNXG5EZWNlbWJlciAxMCwgMjAx
|
||||
NiAxMTowMCBBTSAtIDA3OjAwIFBNIiwKICAgICAgICAiZGlzY291bnRhYmxl
|
||||
IjogdHJ1ZSwKICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAi
|
||||
bWV0YWRhdGEiOiB7fSwKICAgICAgICAicGVyaW9kIjogewogICAgICAgICAg
|
||||
InN0YXJ0IjogMTQ4MDMyOTAyMiwKICAgICAgICAgICJlbmQiOiAxNDgwMzI5
|
||||
MDIyCiAgICAgICAgfSwKICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAg
|
||||
InByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICJxdWFudGl0eSI6IG51bGws
|
||||
CiAgICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgInR5cGUi
|
||||
OiAiaW52b2ljZWl0ZW0iCiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUi
|
||||
OiBmYWxzZSwKICAgICJ0b3RhbF9jb3VudCI6IDMsCiAgICAidXJsIjogIi92
|
||||
MS9pbnZvaWNlcy9pbl8xOUttUDEyc09tZjQ3Tno5Umw2YUtXRjgvbGluZXMi
|
||||
CiAgfSwKICAibGl2ZW1vZGUiOiBmYWxzZSwKICAibWV0YWRhdGEiOiB7fSwK
|
||||
ICAibmV4dF9wYXltZW50X2F0dGVtcHQiOiBudWxsLAogICJwYWlkIjogdHJ1
|
||||
ZSwKICAicGVyaW9kX2VuZCI6IDE0ODAzMjkwMjcsCiAgInBlcmlvZF9zdGFy
|
||||
dCI6IDE0ODAzMjkwMjcsCiAgInJlY2VpcHRfbnVtYmVyIjogbnVsbCwKICAi
|
||||
c3RhcnRpbmdfYmFsYW5jZSI6IDAsCiAgInN0YXRlbWVudF9kZXNjcmlwdG9y
|
||||
IjogbnVsbCwKICAic3Vic2NyaXB0aW9uIjogbnVsbCwKICAic3VidG90YWwi
|
||||
OiA0MjM1MCwKICAidGF4IjogbnVsbCwKICAidGF4X3BlcmNlbnQiOiBudWxs
|
||||
LAogICJ0b3RhbCI6IDQyMzUwLAogICJ3ZWJob29rc19kZWxpdmVyZWRfYXQi
|
||||
OiAxNDgwMzI5MDI3Cn0K
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:28 GMT
|
||||
- request:
|
||||
method: delete
|
||||
uri: https://api.stripe.com/v1/customers/cus_8CzNtM08NVlSGN/sources/card_19KmOv2sOmf47Nz94YYaGGHa
|
||||
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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:30:29 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_9e4YMgucjzDaXM
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: UTF-8
|
||||
string: |
|
||||
{
|
||||
"deleted": true,
|
||||
"id": "card_19KmOv2sOmf47Nz94YYaGGHa"
|
||||
}
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:30:29 GMT
|
||||
recorded_with: VCR 3.0.1
|
@ -0,0 +1,117 @@
|
||||
---
|
||||
http_interactions:
|
||||
- request:
|
||||
method: get
|
||||
uri: https://api.stripe.com/v1/invoices/in_19KmP12sOmf47Nz9Rl6aKWF8
|
||||
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-linux","engine":"ruby","publisher":"stripe","uname":"Linux
|
||||
version 4.4.0-47-generic (buildd@lcy01-03) (gcc version 5.4.0 20160609 (Ubuntu
|
||||
5.4.0-6ubuntu1~16.04.2) ) #68-Ubuntu SMP Wed Oct 26 19:39:52 UTC 2016","hostname":"sylvain-sleede-pc"}'
|
||||
response:
|
||||
status:
|
||||
code: 200
|
||||
message: OK
|
||||
headers:
|
||||
Server:
|
||||
- nginx
|
||||
Date:
|
||||
- Mon, 28 Nov 2016 10:42:47 GMT
|
||||
Content-Type:
|
||||
- application/json
|
||||
Content-Length:
|
||||
- '2535'
|
||||
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_9e4kXKKT6XjyhI
|
||||
Stripe-Version:
|
||||
- '2015-10-16'
|
||||
Strict-Transport-Security:
|
||||
- max-age=31556926; includeSubDomains
|
||||
body:
|
||||
encoding: ASCII-8BIT
|
||||
string: !binary |-
|
||||
ewogICJpZCI6ICJpbl8xOUttUDEyc09tZjQ3Tno5Umw2YUtXRjgiLAogICJv
|
||||
YmplY3QiOiAiaW52b2ljZSIsCiAgImFtb3VudF9kdWUiOiA0MjM1MCwKICAi
|
||||
YXBwbGljYXRpb25fZmVlIjogbnVsbCwKICAiYXR0ZW1wdF9jb3VudCI6IDEs
|
||||
CiAgImF0dGVtcHRlZCI6IHRydWUsCiAgImNoYXJnZSI6ICJjaF8xOUttUDIy
|
||||
c09tZjQ3Tno5M2lmYklVMmkiLAogICJjbG9zZWQiOiB0cnVlLAogICJjdXJy
|
||||
ZW5jeSI6ICJ1c2QiLAogICJjdXN0b21lciI6ICJjdXNfOEN6TnRNMDhOVmxT
|
||||
R04iLAogICJkYXRlIjogMTQ4MDMyOTAyNywKICAiZGVzY3JpcHRpb24iOiBu
|
||||
dWxsLAogICJkaXNjb3VudCI6IG51bGwsCiAgImVuZGluZ19iYWxhbmNlIjog
|
||||
MCwKICAiZm9yZ2l2ZW4iOiBmYWxzZSwKICAibGluZXMiOiB7CiAgICAib2Jq
|
||||
ZWN0IjogImxpc3QiLAogICAgImRhdGEiOiBbCiAgICAgIHsKICAgICAgICAi
|
||||
aWQiOiAiaWlfMTlLbU94MnNPbWY0N056OVhJenZUakxDIiwKICAgICAgICAi
|
||||
b2JqZWN0IjogImxpbmVfaXRlbSIsCiAgICAgICAgImFtb3VudCI6IC0xMDAw
|
||||
LAogICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICJkZXNjcmlw
|
||||
dGlvbiI6ICJ3YWxsZXQgLTEwLjAiLAogICAgICAgICJkaXNjb3VudGFibGUi
|
||||
OiBmYWxzZSwKICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAi
|
||||
bWV0YWRhdGEiOiB7fSwKICAgICAgICAicGVyaW9kIjogewogICAgICAgICAg
|
||||
InN0YXJ0IjogMTQ4MDMyOTAyMywKICAgICAgICAgICJlbmQiOiAxNDgwMzI5
|
||||
MDIzCiAgICAgICAgfSwKICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAg
|
||||
InByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICJxdWFudGl0eSI6IG51bGws
|
||||
CiAgICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgInR5cGUi
|
||||
OiAiaW52b2ljZWl0ZW0iCiAgICAgIH0sCiAgICAgIHsKICAgICAgICAiaWQi
|
||||
OiAiaWlfMTlLbU93MnNPbWY0N056OWZNZ2pISWhnIiwKICAgICAgICAib2Jq
|
||||
ZWN0IjogImxpbmVfaXRlbSIsCiAgICAgICAgImFtb3VudCI6IC03NjUwLAog
|
||||
ICAgICAgICJjdXJyZW5jeSI6ICJ1c2QiLAogICAgICAgICJkZXNjcmlwdGlv
|
||||
biI6ICJjb3Vwb24gU1VOTllGQUJMQUIgLSByZXNlcnZhdGlvbiIsCiAgICAg
|
||||
ICAgImRpc2NvdW50YWJsZSI6IGZhbHNlLAogICAgICAgICJsaXZlbW9kZSI6
|
||||
IGZhbHNlLAogICAgICAgICJtZXRhZGF0YSI6IHt9LAogICAgICAgICJwZXJp
|
||||
b2QiOiB7CiAgICAgICAgICAic3RhcnQiOiAxNDgwMzI5MDIyLAogICAgICAg
|
||||
ICAgImVuZCI6IDE0ODAzMjkwMjIKICAgICAgICB9LAogICAgICAgICJwbGFu
|
||||
IjogbnVsbCwKICAgICAgICAicHJvcmF0aW9uIjogZmFsc2UsCiAgICAgICAg
|
||||
InF1YW50aXR5IjogbnVsbCwKICAgICAgICAic3Vic2NyaXB0aW9uIjogbnVs
|
||||
bCwKICAgICAgICAidHlwZSI6ICJpbnZvaWNlaXRlbSIKICAgICAgfSwKICAg
|
||||
ICAgewogICAgICAgICJpZCI6ICJpaV8xOUttT3cyc09tZjQ3Tno5ZjBQYkti
|
||||
SHEiLAogICAgICAgICJvYmplY3QiOiAibGluZV9pdGVtIiwKICAgICAgICAi
|
||||
YW1vdW50IjogNTEwMDAsCiAgICAgICAgImN1cnJlbmN5IjogInVzZCIsCiAg
|
||||
ICAgICAgImRlc2NyaXB0aW9uIjogIlJhZGlvIG51bcOpcmlxdWUgXG5EZWNl
|
||||
bWJlciAwOCwgMjAxNiAxMTowMCBBTSAtIDA3OjAwIFBNXG5EZWNlbWJlciAw
|
||||
OSwgMjAxNiAxMTowMCBBTSAtIDA3OjAwIFBNXG5EZWNlbWJlciAxMCwgMjAx
|
||||
NiAxMTowMCBBTSAtIDA3OjAwIFBNIiwKICAgICAgICAiZGlzY291bnRhYmxl
|
||||
IjogdHJ1ZSwKICAgICAgICAibGl2ZW1vZGUiOiBmYWxzZSwKICAgICAgICAi
|
||||
bWV0YWRhdGEiOiB7fSwKICAgICAgICAicGVyaW9kIjogewogICAgICAgICAg
|
||||
InN0YXJ0IjogMTQ4MDMyOTAyMiwKICAgICAgICAgICJlbmQiOiAxNDgwMzI5
|
||||
MDIyCiAgICAgICAgfSwKICAgICAgICAicGxhbiI6IG51bGwsCiAgICAgICAg
|
||||
InByb3JhdGlvbiI6IGZhbHNlLAogICAgICAgICJxdWFudGl0eSI6IG51bGws
|
||||
CiAgICAgICAgInN1YnNjcmlwdGlvbiI6IG51bGwsCiAgICAgICAgInR5cGUi
|
||||
OiAiaW52b2ljZWl0ZW0iCiAgICAgIH0KICAgIF0sCiAgICAiaGFzX21vcmUi
|
||||
OiBmYWxzZSwKICAgICJ0b3RhbF9jb3VudCI6IDMsCiAgICAidXJsIjogIi92
|
||||
MS9pbnZvaWNlcy9pbl8xOUttUDEyc09tZjQ3Tno5Umw2YUtXRjgvbGluZXMi
|
||||
CiAgfSwKICAibGl2ZW1vZGUiOiBmYWxzZSwKICAibWV0YWRhdGEiOiB7fSwK
|
||||
ICAibmV4dF9wYXltZW50X2F0dGVtcHQiOiBudWxsLAogICJwYWlkIjogdHJ1
|
||||
ZSwKICAicGVyaW9kX2VuZCI6IDE0ODAzMjkwMjcsCiAgInBlcmlvZF9zdGFy
|
||||
dCI6IDE0ODAzMjkwMjcsCiAgInJlY2VpcHRfbnVtYmVyIjogbnVsbCwKICAi
|
||||
c3RhcnRpbmdfYmFsYW5jZSI6IDAsCiAgInN0YXRlbWVudF9kZXNjcmlwdG9y
|
||||
IjogbnVsbCwKICAic3Vic2NyaXB0aW9uIjogbnVsbCwKICAic3VidG90YWwi
|
||||
OiA0MjM1MCwKICAidGF4IjogbnVsbCwKICAidGF4X3BlcmNlbnQiOiBudWxs
|
||||
LAogICJ0b3RhbCI6IDQyMzUwLAogICJ3ZWJob29rc19kZWxpdmVyZWRfYXQi
|
||||
OiAxNDgwMzI5MDI3Cn0K
|
||||
http_version:
|
||||
recorded_at: Mon, 28 Nov 2016 10:42:47 GMT
|
||||
recorded_with: VCR 3.0.1
|
Loading…
x
Reference in New Issue
Block a user