1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2025-02-26 20:54:21 +01:00

[WIP] fix tests

This commit is contained in:
Sylvain 2021-10-14 18:20:10 +02:00
parent 336a4b789c
commit 315e899540
21 changed files with 4951 additions and 5071 deletions

View File

@ -99,6 +99,8 @@ class API::StripeController < API::PaymentsController
if subscription&.status == 'active'
res = on_payment_success(subscription.latest_invoice.payment_intent, cart)
render generate_payment_response(subscription.latest_invoice.payment_intent, 'subscription', res)
else
render generate_payment_response(subscription.latest_invoice.payment_intent, 'subscription', nil, subscription.id)
end
rescue Stripe::InvalidRequestError => e
render json: e, status: :unprocessable_entity

View File

@ -26,6 +26,10 @@ interface FreeExtendModalProps {
* Modal dialog shown to extend the current subscription of a customer, for free
*/
const FreeExtendModal: React.FC<FreeExtendModalProps> = ({ isOpen, toggleModal, subscription, customerId, onError, onSuccess }) => {
// we do not render the modal if the subscription was not provided
if (!subscription) return null;
const { t } = useTranslation('admin');
const [expirationDate, setExpirationDate] = useState<Date>(new Date(subscription.expired_at));

View File

@ -35,6 +35,10 @@ interface RenewModalProps {
* Modal dialog shown to renew the current subscription of a customer, for free
*/
const RenewModal: React.FC<RenewModalProps> = ({ isOpen, toggleModal, subscription, customer, operator, onError, onSuccess }) => {
// we do not render the modal if the subscription was not provided
if (!subscription) return null;
const { t } = useTranslation('admin');
const [expirationDate, setExpirationDate] = useState<Date>(new Date());
@ -45,8 +49,6 @@ const RenewModal: React.FC<RenewModalProps> = ({ isOpen, toggleModal, subscripti
// on init, we compute the new expiration date
useEffect(() => {
if (!subscription) return;
setExpirationDate(moment(subscription.expired_at)
.add(subscription.plan.interval_count, subscription.plan.interval)
.toDate());
@ -57,13 +59,12 @@ const RenewModal: React.FC<RenewModalProps> = ({ isOpen, toggleModal, subscripti
// when the payment schedule is toggled (requested/ignored), we update the cart accordingly
useEffect(() => {
if (!subscription) return;
setCart({
customer_id: customer.id,
items: [{
subscription: {
plan_id: subscription.plan.id
plan_id: subscription.plan.id,
start_at: subscription.expired_at
}
}],
payment_method: PaymentMethod.Other,
@ -102,9 +103,6 @@ const RenewModal: React.FC<RenewModalProps> = ({ isOpen, toggleModal, subscripti
setLocalPaymentModal(!localPaymentModal);
};
// we do not render the modal if the subscription was not provided
if (!subscription) return null;
return (
<FabModal isOpen={isOpen}
toggleModal={toggleModal}

View File

@ -9,7 +9,8 @@ export interface Subscription {
}
export interface SubscriptionRequest {
plan_id: number
plan_id: number,
start_at?: Date
}
export interface UpdateSubscriptionRequest {

View File

@ -4,17 +4,19 @@
class CartItem::PaymentSchedule
attr_reader :requested
def initialize(plan, coupon, requested)
def initialize(plan, coupon, requested, customer, start_at = nil)
raise TypeError unless coupon.is_a? CartItem::Coupon
@plan = plan
@coupon = coupon
@requested = requested
@customer = customer
@start_at = start_at
end
def schedule(total, total_without_coupon)
schedule = if @requested && @plan&.monthly_payment
PaymentScheduleService.new.compute(@plan, total_without_coupon, coupon: @coupon.coupon)
PaymentScheduleService.new.compute(@plan, total_without_coupon, @customer, coupon: @coupon.coupon, start_at: @start_at)
else
nil
end

View File

@ -2,11 +2,14 @@
# A subscription added to the shopping cart
class CartItem::Subscription < CartItem::BaseItem
def initialize(plan, customer)
attr_reader :start_at
def initialize(plan, customer, start_at = nil)
raise TypeError unless plan.is_a? Plan
@plan = plan
@customer = customer
@start_at = start_at
super
end
@ -30,7 +33,8 @@ class CartItem::Subscription < CartItem::BaseItem
def to_object
::Subscription.new(
plan_id: @plan.id,
statistic_profile_id: StatisticProfile.find_by(user: @customer).id
statistic_profile_id: StatisticProfile.find_by(user: @customer).id,
start_at: @start_at
)
end
end

View File

@ -89,10 +89,10 @@ class ShoppingCart
PaymentScheduleService.new.create(
objects,
price[:before_coupon],
@customer,
coupon: @coupon.coupon,
operator: @operator,
payment_method: @payment_method,
user: @customer,
payment_id: payment_id,
payment_type: payment_type
)

View File

@ -28,7 +28,7 @@ class CartService
end
coupon = CartItem::Coupon.new(@customer, @operator, cart_items[:coupon_code])
schedule = CartItem::PaymentSchedule.new(plan_info[:plan], coupon, cart_items[:payment_schedule])
schedule = CartItem::PaymentSchedule.new(plan_info[:plan], coupon, cart_items[:payment_schedule], @customer, plan_info[:subscription]&.start_at)
ShoppingCart.new(
@customer,
@ -42,19 +42,22 @@ class CartService
def from_payment_schedule(payment_schedule)
@customer = payment_schedule.user
plan = payment_schedule.payment_schedule_objects.find { |pso| pso.object_type == Subscription.name }&.subscription&.plan
subscription = payment_schedule.payment_schedule_objects.find { |pso| pso.object_type == Subscription.name }&.subscription
plan = subscription&.plan
coupon = CartItem::Coupon.new(@customer, @operator, payment_schedule.coupon&.code)
schedule = CartItem::PaymentSchedule.new(plan, coupon, true)
schedule = CartItem::PaymentSchedule.new(plan, coupon, true, @customer, subscription.start_at)
items = []
payment_schedule.payment_schedule_objects.each do |object|
if object.object_type == Subscription.name
items.push(CartItem::Subscription.new(object.subscription.plan, @customer))
items.push(CartItem::Subscription.new(object.subscription.plan, @customer, object.subscription.start_at))
elsif object.object_type == Reservation.name
items.push(reservable_from_payment_schedule_object(object, plan))
elsif object.object_type == PrepaidPack.name
items.push(CartItem::PrepaidPack.new(object.statistic_profile_prepaid_pack.prepaid_pack_id, @customer))
elsif object.object_type == OfferDay.name
items.push(CartItem::FreeExtension.new(@customer, object.offer_day.subscription, object.offer_day.end_date))
end
end
@ -78,7 +81,7 @@ class CartService
if cart_items[:items][index][:subscription][:plan_id]
new_plan_being_bought = true
plan = Plan.find(cart_items[:items][index][:subscription][:plan_id])
subscription = CartItem::Subscription.new(plan, @customer).to_object
subscription = CartItem::Subscription.new(plan, @customer, cart_items[:items][index][:subscription][:start_at]).to_object
plan
end
elsif @customer.subscribed_plan

View File

@ -6,9 +6,11 @@ class PaymentScheduleService
# Compute a payment schedule for a new subscription to the provided plan
# @param plan {Plan}
# @param total {Number} Total amount of the current shopping cart (which includes this plan) - without coupon
# @param customer {User} the customer
# @param coupon {Coupon} apply this coupon, if any
# @param start_at {DateTime} schedule the PaymentSchedule to start in the future
##
def compute(plan, total, coupon: nil)
def compute(plan, total, customer, coupon: nil, start_at: nil)
other_items = total - plan.amount
# base monthly price of the plan
price = plan.amount
@ -22,7 +24,7 @@ class PaymentScheduleService
end
items = []
(0..deadlines - 1).each do |i|
date = DateTime.current + i.months
date = (start_at || DateTime.current) + i.months
details = { recurring: per_month }
amount = if i.zero?
details[:adjustment] = adjustment.truncate
@ -46,14 +48,16 @@ class PaymentScheduleService
)
end
ps.total = items.map(&:amount).reduce(:+)
ps.invoicing_profile = customer.invoicing_profile
ps.statistic_profile = customer.statistic_profile
{ payment_schedule: ps, items: items }
end
def create(objects, total, coupon: nil, operator: nil, payment_method: nil, user: nil,
def create(objects, total, customer, coupon: nil, operator: nil, payment_method: nil,
payment_id: nil, payment_type: nil)
subscription = objects.find { |item| item.class == Subscription }
schedule = compute(subscription.plan, total, coupon: coupon)
schedule = compute(subscription.plan, total, customer, coupon: coupon, start_at: subscription.start_at)
ps = schedule[:payment_schedule]
items = schedule[:items]
@ -68,8 +72,6 @@ class PaymentScheduleService
ps.payment_gateway_objects.push(pgo)
end
ps.operator_profile = operator.invoicing_profile
ps.invoicing_profile = user.invoicing_profile
ps.statistic_profile = user.statistic_profile
ps.payment_schedule_items = items
ps
end

View File

@ -9,6 +9,7 @@ class Subscriptions::Subscribe
@operator_profile_id = operator_profile_id
end
# TODO, delete this
def extend_subscription(subscription, new_expiration_date)
new_sub = Subscription.create(
plan_id: subscription.plan_id,

View File

@ -0,0 +1,9 @@
# frozen_string_literal: true
# From this migration we save again the start_at field to subscriptions (was removed in 20140703100457_change_start_at_to_expired_at_from_subscription.rb).
# This is used to schedule subscriptions start at a future date
class AddStartAtAgainToSubscription < ActiveRecord::Migration[5.2]
def change
add_column :subscriptions, :start_at, :datetime
end
end

View File

@ -10,7 +10,7 @@
#
# It's strongly recommended that you check this file into your version control system.
ActiveRecord::Schema.define(version: 2020_06_22_135401) do
ActiveRecord::Schema.define(version: 2021_10_14_135151) do
# These are extensions that must be enabled in order to support this database
enable_extension "fuzzystrmatch"
@ -19,8 +19,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
enable_extension "unaccent"
create_table "abuses", id: :serial, force: :cascade do |t|
t.integer "signaled_id"
t.string "signaled_type"
t.integer "signaled_id"
t.string "first_name"
t.string "last_name"
t.string "email"
@ -49,8 +49,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.string "locality"
t.string "country"
t.string "postal_code"
t.integer "placeable_id"
t.string "placeable_type"
t.integer "placeable_id"
t.datetime "created_at"
t.datetime "updated_at"
end
@ -64,8 +64,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
end
create_table "assets", id: :serial, force: :cascade do |t|
t.integer "viewable_id"
t.string "viewable_type"
t.integer "viewable_id"
t.string "attachment"
t.string "type"
t.datetime "created_at"
@ -133,8 +133,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
end
create_table "credits", id: :serial, force: :cascade do |t|
t.integer "creditable_id"
t.string "creditable_type"
t.integer "creditable_id"
t.integer "plan_id"
t.integer "hours"
t.datetime "created_at"
@ -207,6 +207,14 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.index ["user_id"], name: "index_exports_on_user_id"
end
create_table "footprint_debugs", force: :cascade do |t|
t.string "footprint"
t.string "data"
t.string "klass"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "friendly_id_slugs", id: :serial, force: :cascade do |t|
t.string "slug", null: false
t.integer "sluggable_id", null: false
@ -274,21 +282,20 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
create_table "invoice_items", id: :serial, force: :cascade do |t|
t.integer "invoice_id"
t.string "stp_invoice_item_id"
t.integer "amount"
t.datetime "created_at"
t.datetime "updated_at"
t.text "description"
t.integer "subscription_id"
t.integer "invoice_item_id"
t.string "footprint"
t.string "object_type"
t.bigint "object_id"
t.boolean "main"
t.index ["invoice_id"], name: "index_invoice_items_on_invoice_id"
t.index ["object_type", "object_id"], name: "index_invoice_items_on_object_type_and_object_id"
end
create_table "invoices", id: :serial, force: :cascade do |t|
t.integer "invoiced_id"
t.string "invoiced_type"
t.string "stp_invoice_id"
t.integer "total"
t.datetime "created_at"
t.datetime "updated_at"
@ -307,7 +314,6 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.integer "invoicing_profile_id"
t.integer "operator_profile_id"
t.integer "statistic_profile_id"
t.string "stp_payment_intent_id"
t.index ["coupon_id"], name: "index_invoices_on_coupon_id"
t.index ["invoice_id"], name: "index_invoices_on_invoice_id"
t.index ["invoicing_profile_id"], name: "index_invoices_on_invoicing_profile_id"
@ -350,15 +356,15 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
create_table "notifications", id: :serial, force: :cascade do |t|
t.integer "receiver_id"
t.integer "attached_object_id"
t.string "attached_object_type"
t.integer "attached_object_id"
t.integer "notification_type_id"
t.boolean "is_read", default: false
t.datetime "created_at"
t.datetime "updated_at"
t.string "receiver_type"
t.boolean "is_send", default: false
t.jsonb "meta_data", default: {}
t.jsonb "meta_data", default: "{}"
t.index ["notification_type_id"], name: "index_notifications_on_notification_type_id"
t.index ["receiver_id"], name: "index_notifications_on_receiver_id"
end
@ -421,6 +427,72 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.index ["invoicing_profile_id"], name: "index_organizations_on_invoicing_profile_id"
end
create_table "payment_gateway_objects", force: :cascade do |t|
t.string "gateway_object_id"
t.string "gateway_object_type"
t.string "item_type"
t.bigint "item_id"
t.bigint "payment_gateway_object_id"
t.index ["item_type", "item_id"], name: "index_payment_gateway_objects_on_item_type_and_item_id"
t.index ["payment_gateway_object_id"], name: "index_payment_gateway_objects_on_payment_gateway_object_id"
end
create_table "payment_schedule_items", force: :cascade do |t|
t.integer "amount"
t.datetime "due_date"
t.string "state", default: "new"
t.jsonb "details", default: "{}"
t.string "payment_method"
t.string "client_secret"
t.bigint "payment_schedule_id"
t.bigint "invoice_id"
t.string "footprint"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["invoice_id"], name: "index_payment_schedule_items_on_invoice_id"
t.index ["payment_schedule_id"], name: "index_payment_schedule_items_on_payment_schedule_id"
end
create_table "payment_schedule_objects", force: :cascade do |t|
t.string "object_type"
t.bigint "object_id"
t.bigint "payment_schedule_id"
t.boolean "main"
t.string "footprint"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["object_type", "object_id"], name: "index_payment_schedule_objects_on_object_type_and_object_id"
t.index ["payment_schedule_id"], name: "index_payment_schedule_objects_on_payment_schedule_id"
end
create_table "payment_schedules", force: :cascade do |t|
t.integer "total"
t.string "reference"
t.string "payment_method"
t.integer "wallet_amount"
t.bigint "wallet_transaction_id"
t.bigint "coupon_id"
t.string "footprint"
t.string "environment"
t.bigint "invoicing_profile_id"
t.bigint "statistic_profile_id"
t.bigint "operator_profile_id"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["coupon_id"], name: "index_payment_schedules_on_coupon_id"
t.index ["invoicing_profile_id"], name: "index_payment_schedules_on_invoicing_profile_id"
t.index ["operator_profile_id"], name: "index_payment_schedules_on_operator_profile_id"
t.index ["statistic_profile_id"], name: "index_payment_schedules_on_statistic_profile_id"
t.index ["wallet_transaction_id"], name: "index_payment_schedules_on_wallet_transaction_id"
end
create_table "plan_categories", force: :cascade do |t|
t.string "name"
t.integer "weight"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "plans", id: :serial, force: :cascade do |t|
t.string "name"
t.integer "amount"
@ -438,7 +510,10 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.integer "interval_count", default: 1
t.string "slug"
t.boolean "disabled"
t.boolean "monthly_payment"
t.bigint "plan_category_id"
t.index ["group_id"], name: "index_plans_on_group_id"
t.index ["plan_category_id"], name: "index_plans_on_plan_category_id"
end
create_table "plans_availabilities", id: :serial, force: :cascade do |t|
@ -448,6 +523,21 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.index ["plan_id"], name: "index_plans_availabilities_on_plan_id"
end
create_table "prepaid_packs", force: :cascade do |t|
t.string "priceable_type"
t.bigint "priceable_id"
t.bigint "group_id"
t.integer "amount"
t.integer "minutes"
t.string "validity_interval"
t.integer "validity_count"
t.boolean "disabled"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["group_id"], name: "index_prepaid_packs_on_group_id"
t.index ["priceable_type", "priceable_id"], name: "index_prepaid_packs_on_priceable_type_and_priceable_id"
end
create_table "price_categories", id: :serial, force: :cascade do |t|
t.string "name"
t.text "conditions"
@ -458,8 +548,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
create_table "prices", id: :serial, force: :cascade do |t|
t.integer "group_id"
t.integer "plan_id"
t.integer "priceable_id"
t.string "priceable_type"
t.integer "priceable_id"
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
@ -531,6 +621,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.string "slug"
t.datetime "published_at"
t.integer "author_statistic_profile_id"
t.tsvector "search_vector"
t.index ["search_vector"], name: "projects_search_vector_idx", using: :gin
t.index ["slug"], name: "index_projects_on_slug", unique: true
end
@ -566,8 +658,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.text "message"
t.datetime "created_at"
t.datetime "updated_at"
t.integer "reservable_id"
t.string "reservable_type"
t.integer "reservable_id"
t.integer "nb_reserve_places"
t.integer "statistic_profile_id"
t.index ["reservable_type", "reservable_id"], name: "index_reservations_on_reservable_type_and_reservable_id"
@ -576,8 +668,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
create_table "roles", id: :serial, force: :cascade do |t|
t.string "name"
t.integer "resource_id"
t.string "resource_type"
t.integer "resource_id"
t.datetime "created_at"
t.datetime "updated_at"
t.index ["name", "resource_type", "resource_id"], name: "index_roles_on_name_and_resource_type_and_resource_id"
@ -671,6 +763,17 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.boolean "ca", default: true
end
create_table "statistic_profile_prepaid_packs", force: :cascade do |t|
t.bigint "prepaid_pack_id"
t.bigint "statistic_profile_id"
t.integer "minutes_used", default: 0
t.datetime "expires_at"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.index ["prepaid_pack_id"], name: "index_statistic_profile_prepaid_packs_on_prepaid_pack_id"
t.index ["statistic_profile_id"], name: "index_statistic_profile_prepaid_packs_on_statistic_profile_id"
end
create_table "statistic_profile_trainings", id: :serial, force: :cascade do |t|
t.integer "statistic_profile_id"
t.integer "training_id"
@ -729,12 +832,12 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
create_table "subscriptions", id: :serial, force: :cascade do |t|
t.integer "plan_id"
t.string "stp_subscription_id"
t.datetime "created_at"
t.datetime "updated_at"
t.datetime "expiration_date"
t.datetime "canceled_at"
t.integer "statistic_profile_id"
t.datetime "start_at"
t.index ["plan_id"], name: "index_subscriptions_on_plan_id"
t.index ["statistic_profile_id"], name: "index_subscriptions_on_statistic_profile_id"
end
@ -827,7 +930,6 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
t.datetime "updated_at"
t.boolean "is_allow_contact", default: true
t.integer "group_id"
t.string "stp_customer_id"
t.string "username"
t.string "slug"
t.boolean "is_active", default: true
@ -868,15 +970,12 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
create_table "wallet_transactions", id: :serial, force: :cascade do |t|
t.integer "wallet_id"
t.integer "transactable_id"
t.string "transactable_type"
t.string "transaction_type"
t.integer "amount"
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
t.integer "invoicing_profile_id"
t.index ["invoicing_profile_id"], name: "index_wallet_transactions_on_invoicing_profile_id"
t.index ["transactable_type", "transactable_id"], name: "index_wallet_transactions_on_transactable"
t.index ["wallet_id"], name: "index_wallet_transactions_on_wallet_id"
end
@ -909,6 +1008,17 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
add_foreign_key "o_auth2_mappings", "o_auth2_providers"
add_foreign_key "open_api_calls_count_tracings", "open_api_clients"
add_foreign_key "organizations", "invoicing_profiles"
add_foreign_key "payment_gateway_objects", "payment_gateway_objects"
add_foreign_key "payment_schedule_items", "invoices"
add_foreign_key "payment_schedule_items", "payment_schedules"
add_foreign_key "payment_schedule_objects", "payment_schedules"
add_foreign_key "payment_schedules", "coupons"
add_foreign_key "payment_schedules", "invoicing_profiles"
add_foreign_key "payment_schedules", "invoicing_profiles", column: "operator_profile_id"
add_foreign_key "payment_schedules", "statistic_profiles"
add_foreign_key "payment_schedules", "wallet_transactions"
add_foreign_key "plans", "plan_categories"
add_foreign_key "prepaid_packs", "groups"
add_foreign_key "prices", "groups"
add_foreign_key "prices", "plans"
add_foreign_key "project_steps", "projects"
@ -929,6 +1039,8 @@ ActiveRecord::Schema.define(version: 2020_06_22_135401) do
add_foreign_key "spaces_availabilities", "availabilities"
add_foreign_key "spaces_availabilities", "spaces"
add_foreign_key "statistic_custom_aggregations", "statistic_types"
add_foreign_key "statistic_profile_prepaid_packs", "prepaid_packs"
add_foreign_key "statistic_profile_prepaid_packs", "statistic_profiles"
add_foreign_key "statistic_profile_trainings", "statistic_profiles"
add_foreign_key "statistic_profile_trainings", "trainings"
add_foreign_key "statistic_profiles", "groups"

View File

@ -9,7 +9,11 @@ class Integrity::Checksum
def code
dir = Dir.pwd
files = children_files("#{dir}/*")
files = if Rails.env.test?
# in test mode, we compute a "lite" checksum to speed-up test running time
children_files("#{dir}/*")
else
children_files("#{dir}/*")
.concat(children_files("#{dir}/app/**/*"))
.concat(children_files("#{dir}/bin/**/*"))
.concat(children_files("#{dir}/config/**/*"))
@ -23,6 +27,7 @@ class Integrity::Checksum
.concat(children_files("#{dir}/scripts/**/*"))
.concat(children_files("#{dir}/test/**/*"))
.concat(children_files("#{dir}/vendor/**/*"))
end
content = files.map { |f| File.read(f) }.join

View File

@ -15,8 +15,8 @@ class Stripe::Service < Payment::Service
payment_schedule.payment_schedule_items = price_details[:schedule][:items]
first_item = price_details[:schedule][:items].min_by(&:due_date)
subscription = shopping_cart.items.find { |item| item.class == CartItem::Subscription }
reservable_stp_id = shopping_cart.items.find { |item| item.is_a?(CartItem::Reservation) }.to_object
.reservable&.payment_gateway_object&.gateway_object_id
reservable_stp_id = shopping_cart.items.find { |item| item.is_a?(CartItem::Reservation) }&.to_object
&.reservable&.payment_gateway_object&.gateway_object_id
WalletService.debit_user_wallet(payment_schedule, shopping_cart.customer, transaction: false)
handle_wallet_transaction(payment_schedule)
@ -29,7 +29,7 @@ class Stripe::Service < Payment::Service
stripe_key = Setting.get('stripe_secret_key')
Stripe::Subscription.create({
stp_subscription = Stripe::Subscription.create({
customer: shopping_cart.customer.payment_gateway_object.gateway_object_id,
cancel_at: (payment_schedule.payment_schedule_items.max_by(&:due_date).due_date + 1.month).to_i,
add_invoice_items: items,
@ -40,6 +40,14 @@ class Stripe::Service < Payment::Service
default_payment_method: payment_method_id,
expand: %w[latest_invoice.payment_intent]
}, { api_key: stripe_key })
return stp_subscription unless subscription.start_at
Stripe::SubscriptionSchedule.create({
from_subscription: stp_subscription.id,
start_date: subscription.start_at
}, { api_key: stripe_key })
stp_subscription
end
def create_subscription(payment_schedule, payment_intent_id)

View File

@ -705,36 +705,10 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
plan = Plan.find_by(group_id: @user_without_subscription.group.id, type: 'Plan', base_name: 'Abonnement mensualisable')
VCR.use_cassette('reservations_training_subscription_with_payment_schedule') do
post '/api/stripe/payment_schedule',
post '/api/stripe/setup_subscription',
params: {
payment_method_id: stripe_payment_method,
cart_items: {
items: [
{
subscription: {
plan_id: plan.id
}
}
],
payment_schedule: true,
payment_method: 'cart'
}
}.to_json, headers: default_headers
# Check response format & status
assert_equal 200, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
sub = json_response(response.body)
assert_not_nil sub[:id]
post '/api/stripe/confirm_payment_schedule',
params: {
subscription_id: sub[:id],
cart_items: {
payment_schedule: true,
payment_method: 'card',
items: [
{
reservation: {
@ -754,9 +728,19 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
plan_id: plan.id
}
}
]
],
payment_schedule: true,
payment_method: 'cart'
}
}.to_json, headers: default_headers
# Check response format & status
assert_equal 201, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
sub = json_response(response.body)
assert_not_nil sub[:id]
end
# Check response format & status
@ -809,37 +793,10 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
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
post '/api/stripe/payment_schedule',
post '/api/stripe/setup_subscription',
params: {
payment_method_id: stripe_payment_method,
cart_items: {
items: [
{
subscription: {
plan_id: plan.id
}
}
],
payment_schedule: true,
payment_method: 'cart'
}
}.to_json, headers: default_headers
# Check response format & status
assert_equal 200, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
res = json_response(response.body)
assert_not_nil res[:id]
post '/api/stripe/confirm_payment_schedule',
params: {
subscription_id: res[:id],
cart_items: {
coupon_code: 'GIME3EUR',
payment_schedule: true,
payment_method: 'card',
items: [
{
reservation: {
@ -859,9 +816,19 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
plan_id: plan.id
}
}
]
],
payment_schedule: true,
payment_method: 'cart'
}
}.to_json, headers: default_headers
# Check response format & status
assert_equal 201, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
res = json_response(response.body)
assert_not_nil res[:id]
end
# Check response format & status
@ -896,7 +863,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
assert_not_nil payment_schedule.reference
assert_equal 'card', payment_schedule.payment_method
assert_equal 2, payment_schedule.payment_gateway_objects.count
#assert_not_nil payment_schedule.gateway_payment_mean
assert_not_nil payment_schedule.gateway_payment_mean
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

View File

@ -77,7 +77,7 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest
payment_schedule_items_count = PaymentScheduleItem.count
VCR.use_cassette('subscriptions_admin_create_with_payment_schedule') do
post '/api/stripe/payment_schedule',
post '/api/stripe/setup_subscription',
params: {
payment_method_id: stripe_payment_method,
cart_items: {
@ -95,34 +95,15 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest
}.to_json, headers: default_headers
# Check response format & status
assert_equal 200, response.status, response.body
assert_equal 201, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
res = json_response(response.body)
assert_not_nil res[:id]
post '/api/stripe/confirm_payment_schedule',
params: {
subscription_id: res[:id],
cart_items: {
customer_id: user.id,
payment_schedule: true,
payment_method: 'card',
items: [
{
subscription: {
plan_id: plan.id
}
}
]
}
}.to_json, headers: default_headers
end
# Check generalities
assert_equal 201, response.status, response.body
assert_equal Mime[:json], response.content_type
assert_equal invoice_count, Invoice.count, "an invoice was generated but it shouldn't"
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'

View File

@ -195,7 +195,7 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
payment_schedule_items_count = PaymentScheduleItem.count
VCR.use_cassette('subscriptions_user_create_with_payment_schedule') do
post '/api/stripe/payment_schedule',
post '/api/stripe/setup_subscription',
params: {
payment_method_id: stripe_payment_method,
cart_items: {
@ -211,18 +211,68 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
}
}.to_json, headers: default_headers
# Check response format & status
assert_equal 201, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
sub = json_response(response.body)
assert_not_nil sub[:id]
end
# Check generalities
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'
# Check the correct plan was subscribed
result = json_response(response.body)
assert_equal PaymentSchedule.last.id, result[:id], 'payment schedule id does not match'
subscription = PaymentSchedule.find(result[:id]).payment_schedule_objects.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
# Check that the user has the correct subscription
assert_not_nil @user.subscription, "user's subscription was not found"
assert_not_nil @user.subscription.plan, "user's subscribed plan was not found"
assert_equal plan.id, @user.subscription.plan_id, "user's plan does not match"
end
test 'user takes a subscription but does not confirm 3DS' do
plan = Plan.find_by(group_id: @user.group.id, type: 'Plan', base_name: 'Abonnement mensualisable')
payment_schedule_count = PaymentSchedule.count
payment_schedule_items_count = PaymentScheduleItem.count
VCR.use_cassette('subscriptions_user_create_without_3ds_confirmation') do
post '/api/stripe/setup_subscription',
params: {
payment_method_id: stripe_payment_method(error: :require_3ds),
cart_items: {
items: [
{
subscription: {
plan_id: plan.id
}
}
],
payment_schedule: true,
payment_method: 'cart'
}
}.to_json, headers: default_headers
# Check response format & status
assert_equal 200, response.status, response.body
assert_equal Mime[:json], response.content_type
# Check the response
sub = json_response(response.body)
assert_not_nil sub[:id]
res = json_response(response.body)
assert res[:requires_action]
assert_not_nil res[:payment_intent_client_secret]
assert_not_nil res[:subscription_id]
assert_equal 'subscription', res[:type]
# create the subscription
post '/api/stripe/confirm_payment_schedule',
# try to confirm the subscription
post '/api/stripe/confirm_subscription',
params: {
subscription_id: sub[:id],
subscription_id: res[:subscription_id],
cart_items: {
payment_schedule: true,
payment_method: 'card',
@ -238,20 +288,19 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
end
# Check generalities
assert_equal 201, response.status, response.body
assert_equal 200, response.status, response.body
assert_equal Mime[:json], response.content_type
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'
# Check the correct plan was subscribed
result = json_response(response.body)
assert_equal PaymentSchedule.last.id, result[:id], 'payment schedule id does not match'
subscription = PaymentSchedule.find(result[:id]).payment_schedule_objects.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
res = json_response(response.body)
assert res[:requires_action]
assert_not_nil res[:payment_intent_client_secret]
assert_not_nil res[:subscription_id]
assert_equal 'subscription', res[:type]
# Check that the user has the correct subscription
assert_not_nil @user.subscription, "user's subscription was not found"
assert_not_nil @user.subscription.plan, "user's subscribed plan was not found"
assert_equal plan.id, @user.subscription.plan_id, "user's plan does not match"
assert_equal payment_schedule_count, PaymentSchedule.count, 'the payment schedule was created anyway'
assert_equal payment_schedule_items_count, PaymentScheduleItem.count, 'some payment schedule items were created anyway'
# Check that the user has no subscription
assert_nil @user.subscription, "user's subscription was not found"
end
end

View File

@ -57,6 +57,8 @@ class ActiveSupport::TestCase
exp_year = 1964
when /invalid_cvc/
cvc = '99'
when /require_3ds/
number = '4000002760003184'
end
Stripe::PaymentMethod.create(

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long