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:
parent
336a4b789c
commit
315e899540
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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}
|
||||
|
@ -9,7 +9,8 @@ export interface Subscription {
|
||||
}
|
||||
|
||||
export interface SubscriptionRequest {
|
||||
plan_id: number
|
||||
plan_id: number,
|
||||
start_at?: Date
|
||||
}
|
||||
|
||||
export interface UpdateSubscriptionRequest {
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
)
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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,
|
||||
|
@ -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
|
154
db/schema.rb
154
db/schema.rb
@ -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"
|
||||
|
@ -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
|
||||
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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'
|
||||
|
@ -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
|
||||
|
@ -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
Loading…
x
Reference in New Issue
Block a user