1
0
mirror of https://github.com/LaCasemate/fab-manager.git synced 2024-12-01 12:24:28 +01:00

migration to object[]

TODO: fix invoices checksums
This commit is contained in:
Sylvain 2021-05-31 11:52:53 +02:00
parent d942d46632
commit db58ee28c0
15 changed files with 316 additions and 255 deletions

View File

@ -1,7 +1,7 @@
Metrics/LineLength: Metrics/LineLength:
Max: 140 Max: 140
Metrics/MethodLength: Metrics/MethodLength:
Max: 36 Max: 35
Metrics/CyclomaticComplexity: Metrics/CyclomaticComplexity:
Max: 13 Max: 13
Metrics/PerceivedComplexity: Metrics/PerceivedComplexity:

View File

@ -30,7 +30,6 @@ class Reservation < ApplicationRecord
after_commit :notify_member_create_reservation, on: :create after_commit :notify_member_create_reservation, on: :create
after_commit :notify_admin_member_create_reservation, on: :create after_commit :notify_admin_member_create_reservation, on: :create
after_commit :update_credits, on: :create
after_commit :extend_subscription, on: :create after_commit :extend_subscription, on: :create
after_save :update_event_nb_free_places, if: proc { |reservation| reservation.reservable_type == 'Event' } after_save :update_event_nb_free_places, if: proc { |reservation| reservation.reservable_type == 'Event' }
@ -111,10 +110,6 @@ class Reservation < ApplicationRecord
end end
end end
def update_credits
UsersCredits::Manager.new(reservation: self).update_credits
end
def extend_subscription def extend_subscription
SubscriptionExtensionAfterReservation.new(self).extend_subscription_if_eligible SubscriptionExtensionAfterReservation.new(self).extend_subscription_if_eligible
end end

View File

@ -45,19 +45,41 @@ class ShoppingCart
} }
end end
# Build the dataset for the current ShoppingCart and save it into the database.
# Data integrity is guaranteed: all goes right or nothing is saved.
def build_and_save(payment_id, payment_type) def build_and_save(payment_id, payment_type)
price = total price = total
objects = [] objects = []
payment = nil payment = nil
ActiveRecord::Base.transaction do ActiveRecord::Base.transaction do
items.each do |item| items.each do |item|
object = item.to_object objects.push(save_item(item))
object.save end
objects.push(object) update_credits(objects)
raise ActiveRecord::Rollback unless object.errors.empty?
payment = create_payment_document(price, objects, payment_id, payment_type)
WalletService.debit_user_wallet(payment, @customer)
payment.save
payment.post_save(payment_id)
end end
payment = if price[:schedule] { success: objects.map(&:errors).flatten.map(&:empty?).all?, payment: payment, errors: objects.map(&:errors).flatten }
end
private
# Save the object associated with the provided item or raise and Rollback if something wrong append.
def save_item(item)
object = item.to_object
object.save
raise ActiveRecord::Rollback unless object.errors.empty?
object
end
# Create the PaymentDocument associated with this ShoppingCart and return it
def create_payment_document(price, objects, payment_id, payment_type)
if price[:schedule]
PaymentScheduleService.new.create( PaymentScheduleService.new.create(
objects, objects,
price[:before_coupon], price[:before_coupon],
@ -79,10 +101,18 @@ class ShoppingCart
payment_method: @payment_method payment_method: @payment_method
) )
end end
payment.save
payment.post_save(payment_id)
end end
{ success: objects.map(&:errors).flatten.map(&:empty?).all?, payment: payment, errors: objects.map(&:errors).flatten } # Handle the update of the user's credits
# If a subscription has been bought, the credits must be reset first.
# Then, the credits related to reservation(s) can be deducted.
def update_credits(objects)
subscription = objects.find { |o| o.is_a? Subscription }
UsersCredits::Manager.new(user: @customer).reset_credits if subscription
reservations = objects.filter { |o| o.is_a? Reservation }
reservations.each do |r|
UsersCredits::Manager.new(reservation: r).update_credits
end
end end
end end

View File

@ -20,7 +20,6 @@ class Subscription < ApplicationRecord
after_save :notify_member_subscribed_plan after_save :notify_member_subscribed_plan
after_save :notify_admin_subscribed_plan after_save :notify_admin_subscribed_plan
after_save :notify_partner_subscribed_plan, if: :of_partner_plan? after_save :notify_partner_subscribed_plan, if: :of_partner_plan?
after_commit :update_credits, on: :create
def generate_and_save_invoice(operator_profile_id) def generate_and_save_invoice(operator_profile_id)
generate_invoice(operator_profile_id).save generate_invoice(operator_profile_id).save
@ -139,9 +138,4 @@ class Subscription < ApplicationRecord
def of_partner_plan? def of_partner_plan?
plan.is_a?(PartnerPlan) plan.is_a?(PartnerPlan)
end end
# init the user's credits
def update_credits
UsersCredits::Manager.new(user: user).reset_credits
end
end end

View File

@ -15,8 +15,8 @@ class Subscriptions::Subscribe
new_sub = Subscription.create( new_sub = Subscription.create(
plan_id: subscription.plan_id, plan_id: subscription.plan_id,
statistic_profile_id: subscription.statistic_profile_id, statistic_profile_id: subscription.statistic_profile_id,
expiration_date: new_expiration_date
) )
new_sub.expiration_date = new_expiration_date
if new_sub.save if new_sub.save
schedule = subscription.original_payment_schedule schedule = subscription.original_payment_schedule

View File

@ -91,4 +91,20 @@ class WalletService
wallet_amount >= total ? total : wallet_amount wallet_amount >= total ? total : wallet_amount
end end
##
# Subtract the amount of the payment document (Invoice|PaymentSchedule) from the customer's wallet
##
def self.debit_user_wallet(payment, user)
wallet_amount = WalletService.wallet_amount_debit(payment, user)
return unless wallet_amount.present? && wallet_amount != 0
amount = wallet_amount / 100.0
wallet_transaction = WalletService.new(user: user, wallet: user.wallet).debit(amount)
# wallet debit success
raise DebitWalletError unless wallet_transaction
payment.set_wallet_transaction(wallet_amount, wallet_transaction.id)
end
end end

View File

@ -14,7 +14,7 @@ class Stripe::Service < Payment::Service
case payment_schedule.main_object.object_type case payment_schedule.main_object.object_type
when Reservation.name when Reservation.name
subscription = payment_schedule.payment_schedule_objects.find(&:subscription) subscription = payment_schedule.payment_schedule_objects.find(&:subscription).object
reservable_stp_id = payment_schedule.main_object.object.reservable&.payment_gateway_object&.gateway_object_id reservable_stp_id = payment_schedule.main_object.object.reservable&.payment_gateway_object&.gateway_object_id
when Subscription.name when Subscription.name
subscription = payment_schedule.main_object.object subscription = payment_schedule.main_object.object

View File

@ -1,7 +1,10 @@
# frozen_string_literal: true # frozen_string_literal: true
module Events require 'test_helper'
class AsAdminTest < ActionDispatch::IntegrationTest
module Events; end
class Events::AsAdminTest < ActionDispatch::IntegrationTest
setup do setup do
admin = User.with_role(:admin).first admin = User.with_role(:admin).first
login_as(admin, scope: :user) login_as(admin, scope: :user)
@ -197,8 +200,8 @@ module Events
result = json_response(response.body) result = json_response(response.body)
i = Invoice.find(result[:id]) i = Invoice.find(result[:id])
assert_equal e.id, i.main_item.object_id assert_equal e.id, i.main_item.object.reservable_id
assert_equal 'Event', i.main_item.object_type assert_equal 'Event', i.main_item.object.reservable_type
# Check the remaining places were updated successfully # Check the remaining places were updated successfully
e = Event.where(id: event[:id]).first e = Event.where(id: event[:id]).first
@ -209,4 +212,3 @@ module Events
assert_equal (4 * 20) + (4 * 16), i.total / 100.0 assert_equal (4 * 20) + (4 * 16), i.total / 100.0
end end
end end
end

View File

@ -79,11 +79,11 @@ class Events::AsUserTest < ActionDispatch::IntegrationTest
# reservation assertions # reservation assertions
reservation = Reservation.last reservation = Reservation.last
assert reservation.invoice assert reservation.original_invoice
assert_equal 1, reservation.invoice.invoice_items.count assert_equal 1, reservation.original_invoice.invoice_items.count
# invoice assertions # invoice assertions
invoice = reservation.invoice invoice = reservation.original_invoice
refute invoice.payment_gateway_object.blank? refute invoice.payment_gateway_object.blank?
refute invoice.total.blank? refute invoice.total.blank?

View File

@ -473,7 +473,8 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
assert_equal plan.id, @user_without_subscription.subscribed_plan.id assert_equal plan.id, @user_without_subscription.subscribed_plan.id
# reservation assertions # reservation assertions
reservation = Reservation.find(result[:id]) invoice = Invoice.find(result[:id])
reservation = invoice.main_item.object
assert reservation.original_invoice assert reservation.original_invoice
assert_equal 2, reservation.original_invoice.invoice_items.count assert_equal 2, reservation.original_invoice.invoice_items.count
@ -493,7 +494,7 @@ class Reservations::CreateAsAdminTest < ActionDispatch::IntegrationTest
# invoice_items # invoice_items
invoice_items = InvoiceItem.last(2) invoice_items = InvoiceItem.last(2)
assert(invoice_items.any? { |ii| ii.amount == plan.amount && !ii.subscription_id.nil? }) assert(invoice_items.any? { |ii| ii.amount == plan.amount && !ii.subscription.nil? })
assert(invoice_items.any? { |ii| ii.amount.zero? }) assert(invoice_items.any? { |ii| ii.amount.zero? })
# invoice assertions # invoice assertions

View File

@ -774,12 +774,14 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
assert_equal plan.id, @user_without_subscription.subscribed_plan.id, "user's plan does not match" assert_equal plan.id, @user_without_subscription.subscribed_plan.id, "user's plan does not match"
# reservation assertions # reservation assertions
assert reservation.payment_schedule assert reservation.original_payment_schedule
assert_equal payment_schedule.main_object.object, reservation assert_equal payment_schedule.main_object.object, reservation
# Check the answer # Check the answer
reservation = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, reservation[:user][:subscribed_plan][:id], 'subscribed plan does not match' assert_equal payment_schedule.id, result[:id], 'payment schedule id does not match'
subscription = payment_schedule.payment_schedule_objects.find(&:subscription).object
assert_equal plan.id, subscription.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 test 'user reserves a machine and renew a subscription with payment schedule and coupon and wallet' do
@ -831,6 +833,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
cart_items: { cart_items: {
coupon_code: 'GIME3EUR', coupon_code: 'GIME3EUR',
payment_schedule: true, payment_schedule: true,
payment_method: 'card',
items: [ items: [
{ {
reservation: { reservation: {
@ -880,7 +883,7 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
assert_equal plan.id, user.subscribed_plan.id, "user's plan does not match" assert_equal plan.id, user.subscribed_plan.id, "user's plan does not match"
# reservation assertions # reservation assertions
assert reservation.payment_schedule assert reservation.original_payment_schedule
assert_equal payment_schedule.main_object.object, reservation assert_equal payment_schedule.main_object.object, reservation
# payment schedule assertions # payment schedule assertions
@ -897,7 +900,9 @@ class Reservations::CreateTest < ActionDispatch::IntegrationTest
assert_equal payment_schedule.invoicing_profile_id, payment_schedule.operator_profile_id assert_equal payment_schedule.invoicing_profile_id, payment_schedule.operator_profile_id
# Check the answer # Check the answer
reservation = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, reservation[:user][:subscribed_plan][:id], 'subscribed plan does not match' assert_equal payment_schedule.id, result[:id], 'payment schedule id does not match'
subscription = payment_schedule.payment_schedule_objects.find(&:subscription).object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
end end
end end

View File

@ -2,6 +2,8 @@
require 'test_helper' require 'test_helper'
module Subscriptions; end
class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest
setup do setup do
@admin = User.find_by(username: 'admin') @admin = User.find_by(username: 'admin')
@ -31,8 +33,11 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest
assert_equal Mime[:json], response.content_type assert_equal Mime[:json], response.content_type
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' assert_equal Invoice.last.id, result[:id], 'invoice id does not match'
subscription = Invoice.find(result[:id]).invoice_items.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
# Check that the user has only one subscription # Check that the user has only one subscription
assert_equal 1, user.subscriptions.count assert_equal 1, user.subscriptions.count
@ -51,12 +56,13 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest
assert_equal 15, (printer.prices.find_by(group_id: user.group_id, plan_id: user.subscription.plan_id).amount / 100.00), 'machine hourly price does not match' assert_equal 15, (printer.prices.find_by(group_id: user.group_id, plan_id: user.subscription.plan_id).amount / 100.00), 'machine hourly price does not match'
# Check notification was sent to the user # Check notification was sent to the user
notification = Notification.find_by(notification_type_id: NotificationType.find_by_name('notify_member_subscribed_plan'), attached_object_type: 'Subscription', attached_object_id: subscription[:id]) notification = Notification.find_by(notification_type_id: NotificationType.find_by_name('notify_member_subscribed_plan'),
attached_object_type: 'Subscription', attached_object_id: subscription.id)
assert_not_nil notification, 'user notification was not created' assert_not_nil notification, 'user notification was not created'
assert_equal user.id, notification.receiver_id, 'wrong user notified' assert_equal user.id, notification.receiver_id, 'wrong user notified'
# Check generated invoice # Check generated invoice
item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription[:id]) item = InvoiceItem.find_by(object_type: 'Subscription', object_id: subscription.id)
invoice = item.invoice invoice = item.invoice
assert_invoice_pdf invoice assert_invoice_pdf invoice
assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription' assert_equal plan.amount, invoice.total, 'Invoice total price does not match the bought subscription'
@ -121,8 +127,10 @@ class Subscriptions::CreateAsAdminTest < ActionDispatch::IntegrationTest
assert_equal payment_schedule_items_count + 12, PaymentScheduleItem.count, 'missing some payment schedule items' assert_equal payment_schedule_items_count + 12, PaymentScheduleItem.count, 'missing some payment schedule items'
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' 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 # Check that the user has the correct subscription
assert_not_nil user.subscription, "user's subscription was not found" assert_not_nil user.subscription, "user's subscription was not found"

View File

@ -32,8 +32,10 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
assert_equal Mime[:json], response.content_type assert_equal Mime[:json], response.content_type
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' assert_equal Invoice.last.id, result[:id], 'invoice id does not match'
subscription = Invoice.find(result[:id]).invoice_items.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
# Check that the user has only one subscription # Check that the user has only one subscription
assert_equal 1, @user.subscriptions.count assert_equal 1, @user.subscriptions.count
@ -131,8 +133,10 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
assert_equal Mime[:json], response.content_type assert_equal Mime[:json], response.content_type
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' assert_equal Invoice.last.id, result[:id], 'invoice id does not match'
subscription = Invoice.find(result[:id]).invoice_items.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
# Check that the user has the correct subscription # Check that the user has the correct subscription
assert_not_nil @vlonchamp.subscription, "user's subscription was not found" assert_not_nil @vlonchamp.subscription, "user's subscription was not found"
@ -237,8 +241,10 @@ class Subscriptions::CreateAsUserTest < ActionDispatch::IntegrationTest
assert_equal payment_schedule_items_count + 12, PaymentScheduleItem.count, 'missing some payment schedule items' assert_equal payment_schedule_items_count + 12, PaymentScheduleItem.count, 'missing some payment schedule items'
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' 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 # Check that the user has the correct subscription
assert_not_nil @user.subscription, "user's subscription was not found" assert_not_nil @user.subscription, "user's subscription was not found"

View File

@ -31,8 +31,10 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest
assert_equal Mime[:json], response.content_type assert_equal Mime[:json], response.content_type
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' assert_equal Invoice.last.id, result[:id], 'invoice id does not match'
subscription = Invoice.find(result[:id]).invoice_items.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
# Check that the user has the correct subscription # Check that the user has the correct subscription
assert_not_nil user.subscription, "user's subscription was not found" assert_not_nil user.subscription, "user's subscription was not found"
@ -41,8 +43,8 @@ class Subscriptions::RenewAsAdminTest < ActionDispatch::IntegrationTest
assert_equal plan.id, user.subscription.plan_id, "user's plan does not match" assert_equal plan.id, user.subscription.plan_id, "user's plan does not match"
# Check the expiration date # Check the expiration date
assert_equal (user.subscription.created_at + plan.interval_count.send(plan.interval)).iso8601, assert_equal (user.subscription.created_at + plan.interval_count.send(plan.interval)).to_i,
subscription[:expired_at], subscription.expiration_date.to_i,
'subscription expiration date does not match' 'subscription expiration date does not match'
# Check the subscription was correctly saved # Check the subscription was correctly saved

View File

@ -32,8 +32,10 @@ class Subscriptions::RenewAsUserTest < ActionDispatch::IntegrationTest
assert_equal Mime[:json], response.content_type assert_equal Mime[:json], response.content_type
# Check the correct plan was subscribed # Check the correct plan was subscribed
subscription = json_response(response.body) result = json_response(response.body)
assert_equal plan.id, subscription[:plan_id], 'subscribed plan does not match' assert_equal Invoice.last.id, result[:id], 'invoice id does not match'
subscription = Invoice.find(result[:id]).invoice_items.first.object
assert_equal plan.id, subscription.plan_id, 'subscribed plan does not match'
# Check the subscription was correctly saved # Check the subscription was correctly saved
assert_equal 2, @user.subscriptions.count assert_equal 2, @user.subscriptions.count