mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-26 20:54:21 +01:00
improved testing of payment schedules + some fixes
TODO: fix the test rails test test/integration/reservations/create_test.rb Reservations::CreateTest#test_user_reserves_a_machine_and_renew_a_subscription_with_payment_schedule_and_coupon_and_wallet [test/integration/reservations/create_test.rb:841] Minitest::Assertion: Expected: "stripe" Actual: nil
This commit is contained in:
parent
d891690ab8
commit
728ae4310c
2
Procfile
2
Procfile
@ -1,4 +1,4 @@
|
|||||||
#web: bundle exec rails server puma -p $PORT
|
web: bundle exec rails server puma -p $PORT
|
||||||
worker: bundle exec sidekiq -C ./config/sidekiq.yml
|
worker: bundle exec sidekiq -C ./config/sidekiq.yml
|
||||||
wp-client: bin/webpack-dev-server
|
wp-client: bin/webpack-dev-server
|
||||||
wp-server: SERVER_BUNDLE_ONLY=yes bin/webpack --watch
|
wp-server: SERVER_BUNDLE_ONLY=yes bin/webpack --watch
|
||||||
|
@ -938,7 +938,7 @@ Application.Directives.directive('cart', ['$rootScope', '$uibModal', 'dialogs',
|
|||||||
|
|
||||||
return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) {
|
return Wallet.getWalletByUser({ user_id: $scope.user.id }, function (wallet) {
|
||||||
const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount);
|
const amountToPay = helpers.getAmountToPay($scope.amountTotal, wallet.amount);
|
||||||
if ((AuthService.isAuthorized(['member']) && amountToPay > 0) ||
|
if ((AuthService.isAuthorized(['member']) && (amountToPay > 0 || (amountToPay === 0 && hasOtherDeadlines()))) ||
|
||||||
(AuthService.isAuthorized('manager') && $scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) {
|
(AuthService.isAuthorized('manager') && $scope.user.id === $rootScope.currentUser.id && amountToPay > 0)) {
|
||||||
return payByStripe(reservation);
|
return payByStripe(reservation);
|
||||||
} else {
|
} else {
|
||||||
|
@ -17,6 +17,8 @@
|
|||||||
bottom: 0;
|
bottom: 0;
|
||||||
background-color: rgba(0, 0, 0, 0.9);
|
background-color: rgba(0, 0, 0, 0.9);
|
||||||
animation: 0.15s linear fadeIn;
|
animation: 0.15s linear fadeIn;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
.fab-modal-sm { width: 340px; }
|
.fab-modal-sm { width: 340px; }
|
||||||
|
@ -79,6 +79,8 @@
|
|||||||
</select>
|
</select>
|
||||||
<span class="help-block error" ng-show="couponForm['coupon[validity_per_user]'].$dirty && couponForm['coupon[validity_per_user]'].$error.required" translate>{{ 'app.shared.coupon.validity_per_user_is_required' }}</span>
|
<span class="help-block error" ng-show="couponForm['coupon[validity_per_user]'].$dirty && couponForm['coupon[validity_per_user]'].$error.required" translate>{{ 'app.shared.coupon.validity_per_user_is_required' }}</span>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="alert alert-warning" ng-show="coupon.validity_per_user == 'once'" translate>{{ 'app.shared.coupon.warn_validity_once' }}</p>
|
||||||
|
<p class="alert alert-warning" ng-show="coupon.validity_per_user == 'forever'" translate>{{ 'app.shared.coupon.warn_validity_forever' }}</p>
|
||||||
|
|
||||||
<div class="form-group" ng-class="{'has-error': errors['valid_until']}">
|
<div class="form-group" ng-class="{'has-error': errors['valid_until']}">
|
||||||
<label for="coupon[valid_until]" translate>{{ 'app.shared.coupon.valid_until' }}</label>
|
<label for="coupon[valid_until]" translate>{{ 'app.shared.coupon.valid_until' }}</label>
|
||||||
|
@ -17,6 +17,9 @@
|
|||||||
<a ng-href="api/invoices/{{t.invoice.id}}/download" target="_blank" ng-if="t.invoice.id">
|
<a ng-href="api/invoices/{{t.invoice.id}}/download" target="_blank" ng-if="t.invoice.id">
|
||||||
{{::t.invoice.reference}}
|
{{::t.invoice.reference}}
|
||||||
</a>
|
</a>
|
||||||
|
<a ng-href="api/payment_schedules/{{t.payment_schedule.id}}/download" target="_blank" ng-if="t.payment_schedule.id">
|
||||||
|
{{::t.payment_schedule.reference}}
|
||||||
|
</a>
|
||||||
</td>
|
</td>
|
||||||
<td>{{ ::t.user.full_name }}</td>
|
<td>{{ ::t.user.full_name }}</td>
|
||||||
<td ng-class="{'green':t.transaction_type == 'credit', 'red':t.transaction_type == 'debit'}">
|
<td ng-class="{'green':t.transaction_type == 'credit', 'red':t.transaction_type == 'debit'}">
|
||||||
|
@ -32,13 +32,17 @@ class Coupon < ApplicationRecord
|
|||||||
}
|
}
|
||||||
|
|
||||||
def safe_destroy
|
def safe_destroy
|
||||||
if invoices.size.zero?
|
if usages.zero?
|
||||||
destroy
|
destroy
|
||||||
else
|
else
|
||||||
false
|
false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def usages
|
||||||
|
invoices.count + payment_schedule.count
|
||||||
|
end
|
||||||
|
|
||||||
##
|
##
|
||||||
# Check the status of the current coupon. The coupon:
|
# Check the status of the current coupon. The coupon:
|
||||||
# - may have been disabled by an admin,
|
# - may have been disabled by an admin,
|
||||||
|
@ -38,6 +38,7 @@ class Subscription < ApplicationRecord
|
|||||||
end
|
end
|
||||||
|
|
||||||
def cancel
|
def cancel
|
||||||
|
# TODO, currently unused, refactor to use with PaymentSchedule
|
||||||
update_columns(canceled_at: DateTime.current)
|
update_columns(canceled_at: DateTime.current)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
json.extract! coupon, :id, :name, :code, :type, :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.amount_off (coupon.amount_off / 100.00) unless coupon.amount_off.nil?
|
||||||
json.usages coupon.invoices.count
|
json.usages coupon.usages
|
||||||
json.status coupon.status
|
json.status coupon.status
|
||||||
|
@ -10,4 +10,10 @@ json.array!(@wallet_transactions) do |t|
|
|||||||
json.reference t.invoice.reference
|
json.reference t.invoice.reference
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if t.payment_schedule
|
||||||
|
json.payment_schedule do
|
||||||
|
json.id t.payment_schedule.id
|
||||||
|
json.reference t.payment_schedule.reference
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
@ -49,5 +49,19 @@ class StripeWorker
|
|||||||
object.update_attributes(stp_product_id: product.id)
|
object.update_attributes(stp_product_id: product.id)
|
||||||
puts "Stripe product was created for the #{class_name} \##{id}"
|
puts "Stripe product was created for the #{class_name} \##{id}"
|
||||||
end
|
end
|
||||||
|
|
||||||
|
rescue Stripe::InvalidRequestError
|
||||||
|
STDERR.puts "WARNING: saved stp_product_id (#{object.stp_product_id}) does not match on Stripe, recreating..."
|
||||||
|
product = Stripe::Product.create(
|
||||||
|
{
|
||||||
|
name: object.name,
|
||||||
|
metadata: {
|
||||||
|
id: object.id,
|
||||||
|
type: class_name
|
||||||
|
}
|
||||||
|
}, { api_key: Setting.get('stripe_secret_key') }
|
||||||
|
)
|
||||||
|
object.update_attributes(stp_product_id: product.id)
|
||||||
|
puts "Stripe product was created for the #{class_name} \##{id}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -42,11 +42,6 @@ module Fablab
|
|||||||
|
|
||||||
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
# The default locale is :en and all translations from config/locales/*.rb,yml are auto loaded.
|
||||||
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
# config.i18n.load_path += Dir[Rails.root.join('my', 'locales', '*.{rb,yml}').to_s]
|
||||||
#
|
|
||||||
# /!\ ALL locales SHOULD be configured accordingly with this locale. /!\
|
|
||||||
#
|
|
||||||
config.i18n.default_locale = Rails.application.secrets.rails_locale
|
|
||||||
config.i18n.fallbacks = [Rails.application.secrets.app_locale, :en]
|
|
||||||
|
|
||||||
config.to_prepare do
|
config.to_prepare do
|
||||||
Devise::Mailer.layout 'notifications_mailer'
|
Devise::Mailer.layout 'notifications_mailer'
|
||||||
|
@ -5,3 +5,10 @@ I18n.config.available_locales += %i[en en-AU-CA en-GB en-IE en-IN en-NZ en-US en
|
|||||||
es-AR es-CL es-CO es-CR es-DO es-EC es-ES es-MX es-PA es-PE es-US es-VE pt pt-BR zu]
|
es-AR es-CL es-CO es-CR es-DO es-EC es-ES es-MX es-PA es-PE es-US es-VE pt pt-BR zu]
|
||||||
# we allow the Zulu locale (zu) as it is used for In-Context translation
|
# we allow the Zulu locale (zu) as it is used for In-Context translation
|
||||||
# @see https://support.crowdin.com/in-context-localization/
|
# @see https://support.crowdin.com/in-context-localization/
|
||||||
|
|
||||||
|
|
||||||
|
#
|
||||||
|
# /!\ ALL locales SHOULD be configured accordingly with the default_locale. /!\
|
||||||
|
#
|
||||||
|
I18n.config.default_locale = Rails.application.secrets.rails_locale
|
||||||
|
I18n.config.locale = Rails.application.secrets.rails_locale
|
||||||
|
@ -346,7 +346,7 @@ en:
|
|||||||
confirmation_required: "Confirmation required"
|
confirmation_required: "Confirmation required"
|
||||||
do_you_really_want_to_delete_this_coupon: "Do you really want to delete this coupon?"
|
do_you_really_want_to_delete_this_coupon: "Do you really want to delete this coupon?"
|
||||||
coupon_was_successfully_deleted: "Coupon was successfully deleted."
|
coupon_was_successfully_deleted: "Coupon was successfully deleted."
|
||||||
unable_to_delete_the_specified_coupon_already_in_use: "Unable to delete the specified coupon: it is already used with some invoices."
|
unable_to_delete_the_specified_coupon_already_in_use: "Unable to delete the specified coupon: it is already used with some invoices and/or some payment schedules."
|
||||||
unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Unable to delete the specified coupon: an unexpected error occurred."
|
unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Unable to delete the specified coupon: an unexpected error occurred."
|
||||||
send_a_coupon: "Send a coupon"
|
send_a_coupon: "Send a coupon"
|
||||||
coupon: "Coupon"
|
coupon: "Coupon"
|
||||||
|
@ -346,7 +346,7 @@ fr:
|
|||||||
confirmation_required: "Confirmation requise"
|
confirmation_required: "Confirmation requise"
|
||||||
do_you_really_want_to_delete_this_coupon: "Êtes-vous sûr(e) de vouloir supprimer ce code promotionnel ?"
|
do_you_really_want_to_delete_this_coupon: "Êtes-vous sûr(e) de vouloir supprimer ce code promotionnel ?"
|
||||||
coupon_was_successfully_deleted: "Le code promotionnel a bien été supprimé."
|
coupon_was_successfully_deleted: "Le code promotionnel a bien été supprimé."
|
||||||
unable_to_delete_the_specified_coupon_already_in_use: "Impossible de supprimer le code promotionnel : il est utilisé dans des factures."
|
unable_to_delete_the_specified_coupon_already_in_use: "Impossible de supprimer le code promotionnel : il est utilisé dans des factures et/ou des échéanciers."
|
||||||
unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Impossible de supprimer le code promotionnel : une erreur inattendue s'est produite."
|
unable_to_delete_the_specified_coupon_an_unexpected_error_occurred: "Impossible de supprimer le code promotionnel : une erreur inattendue s'est produite."
|
||||||
send_a_coupon: "Envoyer un code promo"
|
send_a_coupon: "Envoyer un code promo"
|
||||||
coupon: "Code promo"
|
coupon: "Code promo"
|
||||||
|
@ -111,6 +111,10 @@ Rails.application.routes.draw do
|
|||||||
get 'first', action: 'first', on: :collection
|
get 'first', action: 'first', on: :collection
|
||||||
end
|
end
|
||||||
|
|
||||||
|
resources :payment_schedules, only: %i[index show] do
|
||||||
|
get 'download', on: :member
|
||||||
|
end
|
||||||
|
|
||||||
resources :i_calendar, only: %i[index create destroy] do
|
resources :i_calendar, only: %i[index create destroy] do
|
||||||
get 'events', on: :member
|
get 'events', on: :member
|
||||||
post 'sync', on: :member
|
post 'sync', on: :member
|
||||||
|
@ -4,15 +4,6 @@
|
|||||||
namespace :fablab do
|
namespace :fablab do
|
||||||
namespace :stripe do
|
namespace :stripe do
|
||||||
|
|
||||||
desc 'Cancel stripe subscriptions'
|
|
||||||
task cancel_subscriptions: :environment do
|
|
||||||
Subscription.where('expiration_date >= ?', DateTime.current.at_beginning_of_day).each do |s|
|
|
||||||
puts "-> Start cancel subscription of #{s.user.email}"
|
|
||||||
s.cancel
|
|
||||||
puts '-> Done'
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
desc 'find any invoices with incoherent total between stripe and DB'
|
desc 'find any invoices with incoherent total between stripe and DB'
|
||||||
task :find_incoherent_invoices, [:start_date] => :environment do |_task, args|
|
task :find_incoherent_invoices, [:start_date] => :environment do |_task, args|
|
||||||
puts 'DEPRECATION WARNING: Will not work for invoices created from version 4.1.0 and above'
|
puts 'DEPRECATION WARNING: Will not work for invoices created from version 4.1.0 and above'
|
||||||
|
4
test/fixtures/coupons.yml
vendored
4
test/fixtures/coupons.yml
vendored
@ -5,7 +5,7 @@ one:
|
|||||||
code: XMAS10
|
code: XMAS10
|
||||||
percent_off: 10
|
percent_off: 10
|
||||||
valid_until: 2015-12-31 23:59:59
|
valid_until: 2015-12-31 23:59:59
|
||||||
max_usages: nil
|
max_usages:
|
||||||
active: true
|
active: true
|
||||||
validity_per_user: once
|
validity_per_user: once
|
||||||
|
|
||||||
@ -32,6 +32,6 @@ cash2:
|
|||||||
code: GIME3EUR
|
code: GIME3EUR
|
||||||
amount_off: 300
|
amount_off: 300
|
||||||
valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
valid_until: <%= 1.year.from_now.utc.strftime('%Y-%m-%d %H:%M:%S.%9N Z') %>
|
||||||
max_usages: nil
|
max_usages:
|
||||||
active: true
|
active: true
|
||||||
validity_per_user: once
|
validity_per_user: once
|
||||||
|
84
test/fixtures/prices.yml
vendored
84
test/fixtures/prices.yml
vendored
@ -2,7 +2,7 @@
|
|||||||
price_1:
|
price_1:
|
||||||
id: 1
|
id: 1
|
||||||
group_id: 1
|
group_id: 1
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 1
|
priceable_id: 1
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 2400
|
amount: 2400
|
||||||
@ -12,7 +12,7 @@ price_1:
|
|||||||
price_2:
|
price_2:
|
||||||
id: 2
|
id: 2
|
||||||
group_id: 2
|
group_id: 2
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 1
|
priceable_id: 1
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 5300
|
amount: 5300
|
||||||
@ -22,7 +22,7 @@ price_2:
|
|||||||
price_5:
|
price_5:
|
||||||
id: 5
|
id: 5
|
||||||
group_id: 1
|
group_id: 1
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 2
|
priceable_id: 2
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 4200
|
amount: 4200
|
||||||
@ -32,7 +32,7 @@ price_5:
|
|||||||
price_6:
|
price_6:
|
||||||
id: 6
|
id: 6
|
||||||
group_id: 2
|
group_id: 2
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 2
|
priceable_id: 2
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 1100
|
amount: 1100
|
||||||
@ -42,7 +42,7 @@ price_6:
|
|||||||
price_9:
|
price_9:
|
||||||
id: 9
|
id: 9
|
||||||
group_id: 1
|
group_id: 1
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 3
|
priceable_id: 3
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 4100
|
amount: 4100
|
||||||
@ -52,7 +52,7 @@ price_9:
|
|||||||
price_10:
|
price_10:
|
||||||
id: 10
|
id: 10
|
||||||
group_id: 2
|
group_id: 2
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 3
|
priceable_id: 3
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 5300
|
amount: 5300
|
||||||
@ -62,7 +62,7 @@ price_10:
|
|||||||
price_13:
|
price_13:
|
||||||
id: 13
|
id: 13
|
||||||
group_id: 1
|
group_id: 1
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 4
|
priceable_id: 4
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 900
|
amount: 900
|
||||||
@ -72,7 +72,7 @@ price_13:
|
|||||||
price_14:
|
price_14:
|
||||||
id: 14
|
id: 14
|
||||||
group_id: 2
|
group_id: 2
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 4
|
priceable_id: 4
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 5100
|
amount: 5100
|
||||||
@ -82,7 +82,7 @@ price_14:
|
|||||||
price_17:
|
price_17:
|
||||||
id: 17
|
id: 17
|
||||||
group_id: 1
|
group_id: 1
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 5
|
priceable_id: 5
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 1600
|
amount: 1600
|
||||||
@ -92,7 +92,7 @@ price_17:
|
|||||||
price_18:
|
price_18:
|
||||||
id: 18
|
id: 18
|
||||||
group_id: 2
|
group_id: 2
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 5
|
priceable_id: 5
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 2000
|
amount: 2000
|
||||||
@ -102,7 +102,7 @@ price_18:
|
|||||||
price_21:
|
price_21:
|
||||||
id: 21
|
id: 21
|
||||||
group_id: 1
|
group_id: 1
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 6
|
priceable_id: 6
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 3200
|
amount: 3200
|
||||||
@ -112,7 +112,7 @@ price_21:
|
|||||||
price_22:
|
price_22:
|
||||||
id: 22
|
id: 22
|
||||||
group_id: 2
|
group_id: 2
|
||||||
plan_id:
|
plan_id:
|
||||||
priceable_id: 6
|
priceable_id: 6
|
||||||
priceable_type: Machine
|
priceable_type: Machine
|
||||||
amount: 3400
|
amount: 3400
|
||||||
@ -298,3 +298,63 @@ price_42:
|
|||||||
amount: 1000
|
amount: 1000
|
||||||
created_at: 2016-04-04 15:18:28.860220000 Z
|
created_at: 2016-04-04 15:18:28.860220000 Z
|
||||||
updated_at: 2016-04-04 15:18:50.517702000 Z
|
updated_at: 2016-04-04 15:18:50.517702000 Z
|
||||||
|
|
||||||
|
price_43:
|
||||||
|
id: 43
|
||||||
|
group_id: 1
|
||||||
|
plan_id: 4
|
||||||
|
priceable_id: 1
|
||||||
|
priceable_type: Machine
|
||||||
|
amount: 1000
|
||||||
|
created_at: 2016-04-04 15:18:28.836899000 Z
|
||||||
|
updated_at: 2016-04-04 15:18:50.507019000 Z
|
||||||
|
|
||||||
|
price_44:
|
||||||
|
id: 44
|
||||||
|
group_id: 1
|
||||||
|
plan_id: 4
|
||||||
|
priceable_id: 2
|
||||||
|
priceable_type: Machine
|
||||||
|
amount: 1000
|
||||||
|
created_at: 2016-04-04 15:18:28.842674000 Z
|
||||||
|
updated_at: 2016-04-04 15:18:50.508799000 Z
|
||||||
|
|
||||||
|
price_45:
|
||||||
|
id: 45
|
||||||
|
group_id: 1
|
||||||
|
plan_id: 4
|
||||||
|
priceable_id: 3
|
||||||
|
priceable_type: Machine
|
||||||
|
amount: 1500
|
||||||
|
created_at: 2016-04-04 15:18:28.847736000 Z
|
||||||
|
updated_at: 2016-04-04 15:18:50.510437000 Z
|
||||||
|
|
||||||
|
price_46:
|
||||||
|
id: 46
|
||||||
|
group_id: 1
|
||||||
|
plan_id: 4
|
||||||
|
priceable_id: 4
|
||||||
|
priceable_type: Machine
|
||||||
|
amount: 1000
|
||||||
|
created_at: 2016-04-04 15:18:28.852783000 Z
|
||||||
|
updated_at: 2016-04-04 15:18:50.512239000 Z
|
||||||
|
|
||||||
|
price_47:
|
||||||
|
id: 47
|
||||||
|
group_id: 1
|
||||||
|
plan_id: 4
|
||||||
|
priceable_id: 5
|
||||||
|
priceable_type: Machine
|
||||||
|
amount: 800
|
||||||
|
created_at: 2016-04-04 15:18:28.856602000 Z
|
||||||
|
updated_at: 2016-04-04 15:18:50.514062000 Z
|
||||||
|
|
||||||
|
price_48:
|
||||||
|
id: 48
|
||||||
|
group_id: 1
|
||||||
|
plan_id: 4
|
||||||
|
priceable_id: 6
|
||||||
|
priceable_type: Machine
|
||||||
|
amount: 1000
|
||||||
|
created_at: 2016-04-04 15:18:28.860220000 Z
|
||||||
|
updated_at: 2016-04-04 15:18:50.517702000 Z
|
||||||
|
8
test/fixtures/wallet_transactions.yml
vendored
8
test/fixtures/wallet_transactions.yml
vendored
@ -1,7 +1,13 @@
|
|||||||
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/FixtureSet.html
|
||||||
|
|
||||||
transaction1:
|
transaction1:
|
||||||
invoicing_profile_id: 5
|
invoicing_profile_id: 1
|
||||||
wallet: wallet_5
|
wallet: wallet_5
|
||||||
transaction_type: credit
|
transaction_type: credit
|
||||||
amount: 1000
|
amount: 1000
|
||||||
|
|
||||||
|
transaction2:
|
||||||
|
invoicing_profile_id: 1
|
||||||
|
wallet: wallet_7
|
||||||
|
transaction_type: credit
|
||||||
|
amount: 25500
|
||||||
|
2
test/fixtures/wallets.yml
vendored
2
test/fixtures/wallets.yml
vendored
@ -24,4 +24,4 @@ wallet_1:
|
|||||||
|
|
||||||
wallet_7:
|
wallet_7:
|
||||||
invoicing_profile_id: 7
|
invoicing_profile_id: 7
|
||||||
amount: 0
|
amount: 25500
|
||||||
|
@ -742,4 +742,115 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
|
|||||||
reservation = json_response(response.body)
|
reservation = json_response(response.body)
|
||||||
assert_equal plan.id, reservation[:user][:subscribed_plan][:id], 'subscribed plan does not match'
|
assert_equal plan.id, reservation[:user][:subscribed_plan][:id], 'subscribed plan does not match'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
test 'user reserves a machine and renew a subscription with payment schedule and coupon and wallet' do
|
||||||
|
user = User.find_by(username: 'lseguin')
|
||||||
|
login_as(user, scope: :user)
|
||||||
|
|
||||||
|
reservations_count = Reservation.count
|
||||||
|
invoice_count = Invoice.count
|
||||||
|
invoice_items_count = InvoiceItem.count
|
||||||
|
subscriptions_count = Subscription.count
|
||||||
|
user_subscriptions_count = user.subscriptions.count
|
||||||
|
payment_schedule_count = PaymentSchedule.count
|
||||||
|
payment_schedule_items_count = PaymentScheduleItem.count
|
||||||
|
wallet_transactions_count = WalletTransaction.count
|
||||||
|
|
||||||
|
machine = Machine.find(1)
|
||||||
|
availability = machine.availabilities.last
|
||||||
|
plan = Plan.find_by(group_id: user.group.id, type: 'Plan', base_name: 'Abonnement mensualisable')
|
||||||
|
|
||||||
|
VCR.use_cassette('reservations_machine_subscription_with_payment_schedule_coupon_wallet') do
|
||||||
|
get "/api/payments/setup_intent/#{user.id}"
|
||||||
|
|
||||||
|
# Check response format & status
|
||||||
|
assert_equal 200, response.status, response.body
|
||||||
|
assert_equal Mime[:json], response.content_type
|
||||||
|
|
||||||
|
# Check the response
|
||||||
|
setup_intent = json_response(response.body)
|
||||||
|
assert_not_nil setup_intent[:client_secret]
|
||||||
|
assert_not_nil setup_intent[:id]
|
||||||
|
assert_match /^#{setup_intent[:id]}_secret_/, setup_intent[:client_secret]
|
||||||
|
|
||||||
|
# Confirm the intent (normally, this is done on browser-side)
|
||||||
|
stripe_res = Stripe::SetupIntent.confirm(
|
||||||
|
setup_intent[:id],
|
||||||
|
{ payment_method: stripe_payment_method },
|
||||||
|
{ api_key: Setting.get('stripe_secret_key') }
|
||||||
|
)
|
||||||
|
|
||||||
|
# check the confirmation
|
||||||
|
assert_equal setup_intent[:id], stripe_res.id
|
||||||
|
assert_equal 'succeeded', stripe_res.status
|
||||||
|
assert_equal 'off_session', stripe_res.usage
|
||||||
|
|
||||||
|
|
||||||
|
post '/api/payments/confirm_payment_schedule',
|
||||||
|
params: {
|
||||||
|
setup_intent_id: setup_intent[:id],
|
||||||
|
cart_items: {
|
||||||
|
coupon_code: 'GIME3EUR',
|
||||||
|
reservation: {
|
||||||
|
plan_id: plan.id,
|
||||||
|
payment_schedule: true,
|
||||||
|
reservable_id: machine.id,
|
||||||
|
reservable_type: machine.class.name,
|
||||||
|
slots_attributes: [
|
||||||
|
{
|
||||||
|
start_at: availability.start_at.to_s(:iso8601),
|
||||||
|
end_at: (availability.start_at + 1.hour).to_s(:iso8601),
|
||||||
|
availability_id: availability.id
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.to_json, headers: default_headers
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check response format & status
|
||||||
|
assert_equal 201, response.status, response.body
|
||||||
|
assert_equal Mime[:json], response.content_type
|
||||||
|
assert_equal reservations_count + 1, Reservation.count, 'missing the reservation'
|
||||||
|
assert_equal invoice_count, Invoice.count, "an invoice was generated but it shouldn't"
|
||||||
|
assert_equal invoice_items_count, InvoiceItem.count, "some invoice items were generated but they shouldn't"
|
||||||
|
assert_equal 0, UsersCredit.count, "user's credits were not reset"
|
||||||
|
assert_equal subscriptions_count + 1, Subscription.count, 'missing the subscription'
|
||||||
|
assert_equal payment_schedule_count + 1, PaymentSchedule.count, 'missing the payment schedule'
|
||||||
|
assert_equal payment_schedule_items_count + 12, PaymentScheduleItem.count, 'missing some payment schedule items'
|
||||||
|
assert_equal wallet_transactions_count + 1, WalletTransaction.count, 'missing the wallet transaction'
|
||||||
|
|
||||||
|
# get the objects
|
||||||
|
reservation = Reservation.last
|
||||||
|
subscription = Subscription.last
|
||||||
|
payment_schedule = PaymentSchedule.last
|
||||||
|
|
||||||
|
# subscription assertions
|
||||||
|
assert_equal user_subscriptions_count + 1, user.subscriptions.count
|
||||||
|
assert_equal user, subscription.user
|
||||||
|
assert_not_nil user.subscribed_plan, "user's subscribed plan was not found"
|
||||||
|
assert_not_nil user.subscription, "user's subscription was not found"
|
||||||
|
assert_equal plan.id, user.subscribed_plan.id, "user's plan does not match"
|
||||||
|
|
||||||
|
# reservation assertions
|
||||||
|
assert reservation.payment_schedule
|
||||||
|
assert_equal payment_schedule.scheduled, reservation
|
||||||
|
|
||||||
|
# payment schedule assertions
|
||||||
|
assert_not_nil payment_schedule.reference
|
||||||
|
assert_equal 'stripe', payment_schedule.payment_method
|
||||||
|
assert_not_nil payment_schedule.stp_subscription_id
|
||||||
|
assert_not_nil payment_schedule.stp_setup_intent_id
|
||||||
|
assert_not_nil payment_schedule.wallet_transaction
|
||||||
|
assert_equal payment_schedule.ordered_items.first.amount, payment_schedule.wallet_amount
|
||||||
|
assert_equal Coupon.find_by(code: 'GIME3EUR').id, payment_schedule.coupon_id
|
||||||
|
assert_equal 'test', payment_schedule.environment
|
||||||
|
assert payment_schedule.check_footprint
|
||||||
|
assert_equal user.invoicing_profile.id, payment_schedule.invoicing_profile_id
|
||||||
|
assert_equal payment_schedule.invoicing_profile_id, payment_schedule.operator_profile_id
|
||||||
|
|
||||||
|
# Check the answer
|
||||||
|
reservation = json_response(response.body)
|
||||||
|
assert_equal plan.id, reservation[:user][:subscribed_plan][:id], 'subscribed plan does not match'
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
Loading…
x
Reference in New Issue
Block a user