1
0
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:
Du Peng 2022-06-07 16:55:24 +02:00
parent f9bd27ea13
commit c24aad00c4
13 changed files with 93 additions and 7 deletions

View File

@ -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

View File

@ -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

View File

@ -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(

View File

@ -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;
}
}

View File

@ -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();

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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)) ||

View File

@ -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

View File

@ -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.

View File

@ -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'

View File

@ -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