mirror of
https://github.com/LaCasemate/fab-manager.git
synced 2025-02-20 14:54:15 +01:00
check shopping cart items is valid before pay online
This commit is contained in:
parent
f9bd27ea13
commit
c24aad00c4
@ -4,6 +4,7 @@
|
||||
|
||||
- Fix a bug: admins are shown in select member for reservation by admin
|
||||
- Fix a bug: unable to show tours in machines and spaces page
|
||||
- Check shopping cart items is valid before pay online
|
||||
|
||||
## v5.4.2 2022 June 1
|
||||
|
||||
|
@ -53,6 +53,14 @@ class API::PayzenController < API::PaymentsController
|
||||
render json: e, status: :unprocessable_entity
|
||||
end
|
||||
|
||||
def check_cart
|
||||
cart = shopping_cart
|
||||
unless cart.valid?
|
||||
render json: { error: 'unable to pay' }, status: :unprocessable_entity and return
|
||||
end
|
||||
render json: { cart: 'ok' }, status: :ok
|
||||
end
|
||||
|
||||
def check_hash
|
||||
@result = PayZen::Helper.check_hash(params[:algorithm], params[:hash_key], params[:hash], params[:data])
|
||||
end
|
||||
|
@ -19,6 +19,9 @@ class API::StripeController < API::PaymentsController
|
||||
res = nil # json of the API answer
|
||||
|
||||
cart = shopping_cart
|
||||
unless cart.valid?
|
||||
render json: { error: 'unable to pay' }, status: :unprocessable_entity and return
|
||||
end
|
||||
begin
|
||||
amount = debit_amount(cart) # will contains the amount and the details of each invoice lines
|
||||
if params[:payment_method_id].present?
|
||||
@ -71,10 +74,7 @@ class API::StripeController < API::PaymentsController
|
||||
|
||||
def setup_subscription
|
||||
cart = shopping_cart
|
||||
cart.items.each do |item|
|
||||
raise InvalidSubscriptionError unless item.valid?(cart.items)
|
||||
raise InvalidSubscriptionError unless item.to_object.errors.empty?
|
||||
end
|
||||
raise InvalidSubscriptionError unless cart.valid?
|
||||
|
||||
service = Stripe::Service.new
|
||||
method = service.attach_method_as_default(
|
||||
|
@ -46,4 +46,9 @@ export default class PayzenAPI {
|
||||
const res: AxiosResponse<CreateTokenResponse> = await apiClient.post('/api/payzen/update_token', { payment_schedule_id: paymentScheduleId });
|
||||
return res?.data;
|
||||
}
|
||||
|
||||
static async checkCart (cart: ShoppingCart, customer: User): Promise<CreatePaymentResponse> {
|
||||
const res: AxiosResponse<CreatePaymentResponse> = await apiClient.post('/api/payzen/check_cart', { cart_items: cart, customer_id: customer.id });
|
||||
return res?.data;
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ export const PayzenForm: React.FC<PayzenFormProps> = ({ onSubmit, onSuccess, onE
|
||||
try {
|
||||
const { result } = await PayZenKR.current.validateForm();
|
||||
if (result === null) {
|
||||
await PayzenAPI.checkCart(cart, customer);
|
||||
await PayZenKR.current.onSubmit(onPaid);
|
||||
await PayZenKR.current.onError(handleError);
|
||||
await PayZenKR.current.submit();
|
||||
|
@ -2,12 +2,14 @@
|
||||
|
||||
# A discount coupon applied to the whole shopping cart
|
||||
class CartItem::Coupon
|
||||
attr_reader :errors
|
||||
|
||||
# @param coupon {String|Coupon} may be nil or empty string if no coupons are applied
|
||||
def initialize(customer, operator, coupon)
|
||||
@customer = customer
|
||||
@operator = operator
|
||||
@coupon = coupon
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
def coupon
|
||||
@ -27,4 +29,15 @@ class CartItem::Coupon
|
||||
def type
|
||||
'coupon'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
return true if @coupon.nil?
|
||||
|
||||
c = ::Coupon.find_by(code: @coupon)
|
||||
if c.nil? || c.status(@customer.id) != 'active'
|
||||
@errors[:item] = 'coupon is invalid'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
# A payment schedule applied to plan in the shopping cart
|
||||
class CartItem::PaymentSchedule
|
||||
attr_reader :requested
|
||||
attr_reader :requested, :errors
|
||||
|
||||
def initialize(plan, coupon, requested, customer, start_at = nil)
|
||||
raise TypeError unless coupon.is_a? CartItem::Coupon
|
||||
@ -12,6 +12,7 @@ class CartItem::PaymentSchedule
|
||||
@requested = requested
|
||||
@customer = customer
|
||||
@start_at = start_at
|
||||
@errors = {}
|
||||
end
|
||||
|
||||
def schedule(total, total_without_coupon)
|
||||
@ -33,4 +34,12 @@ class CartItem::PaymentSchedule
|
||||
def type
|
||||
'subscription'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
if @plan&.disabled
|
||||
@errors[:item] = 'plan is disabled'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -37,4 +37,12 @@ class CartItem::PrepaidPack < CartItem::BaseItem
|
||||
def type
|
||||
'pack'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
if @pack.disabled
|
||||
@errors[:item] = 'pack is disabled'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -43,7 +43,26 @@ class CartItem::Reservation < CartItem::BaseItem
|
||||
def valid?(all_items)
|
||||
pending_subscription = all_items.find { |i| i.is_a?(CartItem::Subscription) }
|
||||
@slots.each do |slot|
|
||||
availability = Availability.find(slot[:availability_id])
|
||||
availability = Availability.find_by(id: slot[:availability_id])
|
||||
if availability.nil?
|
||||
@errors[:slot] = 'slot availability no exist'
|
||||
return false
|
||||
end
|
||||
|
||||
if availability.available_type == 'machines'
|
||||
s = Slot.find_by(start_at: slot[:start_at], end_at: slot[:end_at], availability_id: slot[:availability_id], canceled_at: nil)
|
||||
unless s.nil?
|
||||
@errors[:slot] = 'slot has reserved'
|
||||
return false
|
||||
end
|
||||
elsif availability.available_type == 'space' && availability.spaces.first.disabled.nil?
|
||||
@errors[:slot] = 'space is disabled'
|
||||
return false
|
||||
elsif availability.completed?
|
||||
@errors[:slot] = 'availability has completed'
|
||||
return false
|
||||
end
|
||||
|
||||
next if availability.plan_ids.empty?
|
||||
next if (@customer.subscribed_plan && availability.plan_ids.include?(@customer.subscribed_plan.id)) ||
|
||||
(pending_subscription && availability.plan_ids.include?(pending_subscription.plan.id)) ||
|
||||
|
@ -41,4 +41,12 @@ class CartItem::Subscription < CartItem::BaseItem
|
||||
def type
|
||||
'subscription'
|
||||
end
|
||||
|
||||
def valid?(_all_items)
|
||||
if @plan.disabled
|
||||
@errors[:item] = 'plan is disabled'
|
||||
return false
|
||||
end
|
||||
true
|
||||
end
|
||||
end
|
||||
|
@ -87,6 +87,19 @@ class ShoppingCart
|
||||
{ success: success, payment: payment, errors: errors }
|
||||
end
|
||||
|
||||
def valid?
|
||||
items.each do |item|
|
||||
next if item.valid?(@items)
|
||||
|
||||
return false
|
||||
end
|
||||
return false unless @coupon.valid?([])
|
||||
|
||||
return false unless @payment_schedule.valid?([])
|
||||
|
||||
true
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
# Save the object associated with the provided item or raise and Rollback if something wrong append.
|
||||
|
@ -214,6 +214,7 @@ Rails.application.routes.draw do
|
||||
post 'payzen/check_hash' => 'payzen#check_hash'
|
||||
post 'payzen/create_token' => 'payzen#create_token'
|
||||
post 'payzen/update_token' => 'payzen#update_token'
|
||||
post 'payzen/check_cart' => 'payzen#check_cart'
|
||||
|
||||
# local payments handling
|
||||
post 'local_payment/confirm_payment' => 'local_payment#confirm_payment'
|
||||
|
@ -141,7 +141,7 @@ class Reservations::RestrictedTest < ActionDispatch::IntegrationTest
|
||||
end
|
||||
|
||||
assert_equal 422, response.status
|
||||
assert_match /slot is restricted for subscribers/, response.body
|
||||
assert_match /unable to pay/, response.body
|
||||
|
||||
assert_equal reservations_count, Reservation.count
|
||||
assert_equal invoices_count, Invoice.count
|
||||
|
Loading…
x
Reference in New Issue
Block a user