mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-01-18 07:52:23 +01:00
(feat) create cart items from the api
This commit is contained in:
parent
42d830b4f8
commit
48a44ff4f3
@ -1,6 +1,6 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# API Controller for manage user's cart
|
||||
# API Controller to manage user's cart
|
||||
class API::CartController < API::ApiController
|
||||
include API::OrderConcern
|
||||
|
||||
@ -13,6 +13,17 @@ class API::CartController < API::ApiController
|
||||
render 'api/orders/show'
|
||||
end
|
||||
|
||||
def create_item
|
||||
authorize @current_order, policy_class: CartPolicy
|
||||
service = Cart::CreateCartItemService.new(@current_order)
|
||||
@item = service.create(params)
|
||||
if @item.save({ context: @current_order.order_items })
|
||||
render 'api/orders/item', status: :created
|
||||
else
|
||||
render json: @item.errors.full_messages, status: :unprocessable_entity
|
||||
end
|
||||
end
|
||||
|
||||
def add_item
|
||||
authorize @current_order, policy_class: CartPolicy
|
||||
@order = Cart::AddItemService.new.call(@current_order, orderable, cart_params[:quantity])
|
||||
|
@ -19,7 +19,7 @@ class CartItem::MachineReservation < CartItem::Reservation
|
||||
'machine'
|
||||
end
|
||||
|
||||
def valid?(all_items)
|
||||
def valid?(all_items = [])
|
||||
cart_item_reservation_slots.each do |slot|
|
||||
same_hour_slots = SlotsReservation.joins(:reservation).where(
|
||||
reservations: { reservable: reservable },
|
||||
|
@ -3,6 +3,7 @@
|
||||
# A prepaid-pack added to the shopping cart
|
||||
class CartItem::PrepaidPack < CartItem::BaseItem
|
||||
belongs_to :prepaid_pack
|
||||
belongs_to :customer_profile, class_name: 'InvoicingProfile'
|
||||
|
||||
def customer
|
||||
customer_profile.user
|
||||
@ -36,11 +37,11 @@ class CartItem::PrepaidPack < CartItem::BaseItem
|
||||
|
||||
def valid?(_all_items)
|
||||
if pack.disabled
|
||||
@errors[:item] = I18n.t('cart_item_validation.pack')
|
||||
errors.add(:prepaid_pack, I18n.t('cart_item_validation.pack'))
|
||||
return false
|
||||
end
|
||||
if pack.group_id != customer.group_id
|
||||
@errors[:group] = "pack is reserved for members of group #{pack.group.name}"
|
||||
errors.add(:group, "pack is reserved for members of group #{pack.group.name}")
|
||||
return false
|
||||
end
|
||||
true
|
||||
|
@ -52,7 +52,7 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
reservable&.name
|
||||
end
|
||||
|
||||
def valid?(all_items)
|
||||
def valid?(all_items = [])
|
||||
pending_subscription = all_items.find { |i| i.is_a?(CartItem::Subscription) }
|
||||
|
||||
reservation_deadline_minutes = Setting.get('reservation_deadline').to_i
|
||||
|
@ -6,7 +6,7 @@ class CartPolicy < ApplicationPolicy
|
||||
!Setting.get('store_hidden') || user&.privileged?
|
||||
end
|
||||
|
||||
%w[add_item remove_item set_quantity refresh_item validate].each do |action|
|
||||
%w[add_item remove_item set_quantity refresh_item validate create_item].each do |action|
|
||||
define_method "#{action}?" do
|
||||
return user.privileged? || (record.statistic_profile_id == user.statistic_profile.id) if user
|
||||
|
||||
|
@ -8,8 +8,8 @@ class Cart::AddItemService
|
||||
item = case orderable
|
||||
when Product
|
||||
add_product(order, orderable, quantity)
|
||||
when Slot
|
||||
add_slot(order, orderable)
|
||||
when /^CartItem::/
|
||||
add_cart_item(order, orderable)
|
||||
else
|
||||
raise Cart::UnknownItemError
|
||||
end
|
||||
@ -42,11 +42,7 @@ class Cart::AddItemService
|
||||
item
|
||||
end
|
||||
|
||||
def add_slot(order, orderable)
|
||||
item = order.order_items.find_by(orderable: orderable)
|
||||
|
||||
item = order.order_items.new(quantity: 1, orderable: orderable, amount: orderable.amount || 0) if item.nil?
|
||||
|
||||
item
|
||||
def add_cart_item(order, orderable)
|
||||
order.order_items.new(quantity: 1, orderable: orderable, amount: orderable.price.amount || 0)
|
||||
end
|
||||
end
|
||||
|
110
app/services/cart/create_cart_item_service.rb
Normal file
110
app/services/cart/create_cart_item_service.rb
Normal file
@ -0,0 +1,110 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
# Provides methods to create new cart items, based on an existing Order
|
||||
class Cart::CreateCartItemService
|
||||
def initialize(order)
|
||||
@order = order
|
||||
@customer = order.user
|
||||
@operator = order.user.privileged? ? order.operator_profile.user : order.user
|
||||
end
|
||||
|
||||
def create(item)
|
||||
key = item.keys.filter { |k| %w[subscription reservation prepaid_pack free_extension].include?(k) }.first
|
||||
case key
|
||||
when 'subscription', :subscription
|
||||
subscription = create_subscription(item.require(:subscription).permit!)
|
||||
update_reservations(subscription)
|
||||
subscription
|
||||
when 'reservation', :reservation
|
||||
create_reservation(item.require(:reservation).permit!)
|
||||
when 'prepaid_pack', :prepaid_pack
|
||||
create_prepaid_pack(item.require(:prepaid_pack).permit!)
|
||||
when 'free_extension', :free_extension
|
||||
create_free_extension(item.require(:free_extension).permit!)
|
||||
else
|
||||
raise NotImplementedError, "unknown item type #{item.keys.first}"
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def create_subscription(cart_item)
|
||||
CartItem::Subscription.new(
|
||||
plan: Plan.find(cart_item[:plan_id]),
|
||||
customer_profile: @customer.invoicing_profile,
|
||||
start_at: cart_item[:start_at]
|
||||
)
|
||||
end
|
||||
|
||||
def update_reservations(new_subscription)
|
||||
@order.order_items
|
||||
.where(orderable_type: %w[CartItem::MachineReservation CartItem::SpaceReservation CartItem::TrainingReservation])
|
||||
.find_each do |reserv|
|
||||
reserv.update(plan: new_subscription.plan, new_subscription: true)
|
||||
end
|
||||
end
|
||||
|
||||
def create_reservation(cart_item)
|
||||
plan_info = subscription_info
|
||||
reservable = cart_item[:reservable_type]&.constantize&.find(cart_item[:reservable_id])
|
||||
case reservable
|
||||
when Machine
|
||||
CartItem::MachineReservation.new(customer_profile: @customer.invoicing_profile,
|
||||
operator_profile: @operator.invoicing_profile,
|
||||
reservable: reservable,
|
||||
cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
|
||||
plan: plan_info[:subscription]&.plan,
|
||||
new_subscription: plan_info[:new_subscription])
|
||||
when Training
|
||||
CartItem::TrainingReservation.new(customer_profile: @customer.invoicing_profile,
|
||||
operator_profile: @operator.invoicing_profile,
|
||||
reservable: reservable,
|
||||
cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
|
||||
plan: plan_info[:subscription]&.plan,
|
||||
new_subscription: plan_info[:new_subscription])
|
||||
when Event
|
||||
CartItem::EventReservation.new(customer_profile: @customer.invoicing_profile,
|
||||
operator_profile: @operator.invoicing_profile,
|
||||
event: reservable,
|
||||
cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
|
||||
normal_tickets: cart_item[:nb_reserve_places],
|
||||
cart_item_event_reservation_tickets_attributes: cart_item[:tickets_attributes] || {})
|
||||
when Space
|
||||
CartItem::SpaceReservation.new(customer_profile: @customer.invoicing_profile,
|
||||
operator_profile: @operator.invoicing_profile,
|
||||
reservable: reservable,
|
||||
cart_item_reservation_slots_attributes: cart_item[:slots_reservations_attributes],
|
||||
plan: plan_info[:subscription]&.plan,
|
||||
new_subscription: plan_info[:new_subscription])
|
||||
else
|
||||
raise NotImplementedError, "unknown reservable type #{reservable}"
|
||||
end
|
||||
end
|
||||
|
||||
def create_prepaid_pack(cart_item)
|
||||
CartItem::PrepaidPack.new(
|
||||
prepaid_pack: PrepaidPack.find(cart_item[:id]),
|
||||
customer_profile: @customer.invoicing_profile
|
||||
)
|
||||
end
|
||||
|
||||
def create_free_extension(cart_item)
|
||||
plan_info = subscription_info
|
||||
CartItem::FreeExtension.new(
|
||||
customer_profile: @customer.invoicing_profile,
|
||||
subscription: plan_info[:subscription],
|
||||
new_expiration_date: cart_item[:end_at]
|
||||
)
|
||||
end
|
||||
|
||||
def subscription_info
|
||||
cart_subscription = @order.order_items.find_by(orderable_type: 'CartItem::Subscription')
|
||||
if cart_subscription
|
||||
{ subscription: cart_subscription, new_subscription: true }
|
||||
elsif @customer.subscribed_plan
|
||||
{ subscription: @customer.subscription, new_subscription: false } unless @customer.subscription.expired_at < DateTime.current
|
||||
else
|
||||
{ subscription: nil, new_subscription: false }
|
||||
end
|
||||
end
|
||||
end
|
4
app/views/api/orders/item.json.jbuilder
Normal file
4
app/views/api/orders/item.json.jbuilder
Normal file
@ -0,0 +1,4 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
json.id @item.id
|
||||
json.type @item.class.name
|
@ -168,6 +168,7 @@ Rails.application.routes.draw do
|
||||
put 'set_offer', on: :collection
|
||||
put 'refresh_item', on: :collection
|
||||
post 'validate', on: :collection
|
||||
post 'create_item', on: :collection
|
||||
end
|
||||
resources :checkout, only: %i[] do
|
||||
post 'payment', on: :collection
|
||||
|
18
db/schema.rb
18
db/schema.rb
@ -19,8 +19,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
enable_extension "unaccent"
|
||||
|
||||
create_table "abuses", id: :serial, force: :cascade do |t|
|
||||
t.string "signaled_type"
|
||||
t.integer "signaled_id"
|
||||
t.string "signaled_type"
|
||||
t.string "first_name"
|
||||
t.string "last_name"
|
||||
t.string "email"
|
||||
@ -68,8 +68,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
t.string "locality"
|
||||
t.string "country"
|
||||
t.string "postal_code"
|
||||
t.string "placeable_type"
|
||||
t.integer "placeable_id"
|
||||
t.string "placeable_type"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
end
|
||||
@ -93,8 +93,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
end
|
||||
|
||||
create_table "assets", id: :serial, force: :cascade do |t|
|
||||
t.string "viewable_type"
|
||||
t.integer "viewable_id"
|
||||
t.string "viewable_type"
|
||||
t.string "attachment"
|
||||
t.string "type"
|
||||
t.datetime "created_at"
|
||||
@ -281,8 +281,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
end
|
||||
|
||||
create_table "credits", id: :serial, force: :cascade do |t|
|
||||
t.string "creditable_type"
|
||||
t.integer "creditable_id"
|
||||
t.string "creditable_type"
|
||||
t.integer "plan_id"
|
||||
t.integer "hours"
|
||||
t.datetime "created_at"
|
||||
@ -524,15 +524,15 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
|
||||
create_table "notifications", id: :serial, force: :cascade do |t|
|
||||
t.integer "receiver_id"
|
||||
t.string "attached_object_type"
|
||||
t.integer "attached_object_id"
|
||||
t.string "attached_object_type"
|
||||
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
|
||||
@ -772,8 +772,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
create_table "prices", id: :serial, force: :cascade do |t|
|
||||
t.integer "group_id"
|
||||
t.integer "plan_id"
|
||||
t.string "priceable_type"
|
||||
t.integer "priceable_id"
|
||||
t.string "priceable_type"
|
||||
t.integer "amount"
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
@ -976,8 +976,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
t.text "message"
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.string "reservable_type"
|
||||
t.integer "reservable_id"
|
||||
t.string "reservable_type"
|
||||
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"
|
||||
@ -986,8 +986,8 @@ ActiveRecord::Schema.define(version: 2023_01_31_104958) do
|
||||
|
||||
create_table "roles", id: :serial, force: :cascade do |t|
|
||||
t.string "name"
|
||||
t.string "resource_type"
|
||||
t.integer "resource_id"
|
||||
t.string "resource_type"
|
||||
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"
|
||||
|
165
test/integration/order/create_cart_item_test.rb
Normal file
165
test/integration/order/create_cart_item_test.rb
Normal file
@ -0,0 +1,165 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
require 'test_helper'
|
||||
|
||||
class CreateCartItemTest < ActionDispatch::IntegrationTest
|
||||
setup do
|
||||
@user = User.find_by(username: 'pdurand')
|
||||
login_as(@user, scope: :user)
|
||||
@order = Cart::FindOrCreateService.new(@user).call(nil)
|
||||
end
|
||||
|
||||
test 'create a subscription' do
|
||||
plan = Plan.first
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
subscription: {
|
||||
plan_id: plan.id
|
||||
}
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::Subscription
|
||||
assert_equal plan, resource.plan
|
||||
end
|
||||
|
||||
test 'create a machine reservation' do
|
||||
machine = Machine.first
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
reservation: {
|
||||
reservable_id: machine.id,
|
||||
reservable_type: 'Machine',
|
||||
slots_reservations_attributes: [
|
||||
{ slot_id: machine.availabilities.last&.slots&.last&.id }
|
||||
]
|
||||
}
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::MachineReservation
|
||||
assert_equal machine, resource.reservable
|
||||
end
|
||||
|
||||
test 'create a space reservation' do
|
||||
space = Space.first
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
reservation: {
|
||||
reservable_id: space.id,
|
||||
reservable_type: 'Space',
|
||||
slots_reservations_attributes: [
|
||||
{ slot_id: space.availabilities.last&.slots&.last&.id }
|
||||
]
|
||||
}
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::SpaceReservation
|
||||
assert_equal space, resource.reservable
|
||||
end
|
||||
|
||||
test 'create a training reservation' do
|
||||
training = Training.first
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
reservation: {
|
||||
reservable_id: training.id,
|
||||
reservable_type: 'Training',
|
||||
slots_reservations_attributes: [
|
||||
{ slot_id: training.availabilities.last&.slots&.last&.id }
|
||||
]
|
||||
}
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::TrainingReservation
|
||||
assert_equal training, resource.reservable
|
||||
end
|
||||
|
||||
test 'create an event reservation' do
|
||||
event = Event.find(4)
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
reservation: {
|
||||
reservable_id: event.id,
|
||||
reservable_type: 'Event',
|
||||
slots_reservations_attributes: [
|
||||
{ slot_id: event.availability.slots.last&.id }
|
||||
],
|
||||
nb_reserve_places: 2
|
||||
}
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::EventReservation
|
||||
assert_equal event, resource.event
|
||||
assert_equal 2, resource.normal_tickets
|
||||
end
|
||||
|
||||
test 'create a prepaid-pack' do
|
||||
pack = PrepaidPack.first
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
prepaid_pack: { id: pack.id }
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::PrepaidPack
|
||||
assert_equal pack.id, resource.prepaid_pack_id
|
||||
end
|
||||
|
||||
test 'create a free-extension for a subscription' do
|
||||
subscription = @user.subscription
|
||||
post '/api/cart/create_item',
|
||||
params: {
|
||||
order_token: @order.token,
|
||||
free_extension: { end_at: subscription.expiration_date + 1.month }
|
||||
}
|
||||
# general assertions
|
||||
assert_equal 201, response.status
|
||||
assert_equal Mime[:json], response.content_type
|
||||
|
||||
# Check the cart item was created correctly
|
||||
res = json_response(response.body)
|
||||
resource = res[:type].classify.constantize.find(res[:id])
|
||||
assert resource.is_a? CartItem::FreeExtension
|
||||
assert_equal subscription.id, resource.subscription_id
|
||||
end
|
||||
end
|
Loading…
x
Reference in New Issue
Block a user