From 8a8ce607b7a91fed7facd19102526ea5bd611e14 Mon Sep 17 00:00:00 2001 From: Du Peng Date: Thu, 25 Aug 2022 11:46:14 +0200 Subject: [PATCH] check product is valid and in stock before payment --- app/exceptions/cart/zero_price_error.rb | 5 +++++ app/models/order.rb | 4 ++-- app/services/checkout/payment_service.rb | 4 ++++ app/services/orders/in_stock_service.rb | 23 +++++++++++++++++++++++ app/services/orders/order_service.rb | 18 ++++++++++++++++++ app/services/payments/payment_concern.rb | 2 +- app/services/payments/payzen_service.rb | 2 ++ app/services/payments/stripe_service.rb | 3 +++ 8 files changed, 58 insertions(+), 3 deletions(-) create mode 100644 app/exceptions/cart/zero_price_error.rb create mode 100644 app/services/orders/in_stock_service.rb create mode 100644 app/services/orders/order_service.rb diff --git a/app/exceptions/cart/zero_price_error.rb b/app/exceptions/cart/zero_price_error.rb new file mode 100644 index 000000000..7ac80e19f --- /dev/null +++ b/app/exceptions/cart/zero_price_error.rb @@ -0,0 +1,5 @@ +# frozen_string_literal: true + +# Raised when order amount = 0 +class Cart::ZeroPriceError < StandardError +end diff --git a/app/models/order.rb b/app/models/order.rb index ff7b72d7d..b1a70cc5d 100644 --- a/app/models/order.rb +++ b/app/models/order.rb @@ -5,10 +5,10 @@ class Order < ApplicationRecord belongs_to :statistic_profile has_many :order_items, dependent: :destroy - ALL_STATES = %w[cart].freeze + ALL_STATES = %w[cart in_progress ready canceled return].freeze enum state: ALL_STATES.zip(ALL_STATES).to_h - PAYMENT_STATES = %w[paid failed].freeze + PAYMENT_STATES = %w[paid failed refunded].freeze enum payment_state: PAYMENT_STATES.zip(PAYMENT_STATES).to_h validates :token, :state, presence: true diff --git a/app/services/checkout/payment_service.rb b/app/services/checkout/payment_service.rb index ab7b6f954..2f4de1d55 100644 --- a/app/services/checkout/payment_service.rb +++ b/app/services/checkout/payment_service.rb @@ -6,6 +6,10 @@ class Checkout::PaymentService require 'stripe/helper' def payment(order, operator, payment_id = '') + raise Cart::OutStockError unless Orders::OrderService.new.in_stock?(order, 'external') + + raise Cart::InactiveProductError unless Orders::OrderService.new.all_products_is_active? + if operator.member? if Stripe::Helper.enabled? Payments::StripeService.new.payment(order, payment_id) diff --git a/app/services/orders/in_stock_service.rb b/app/services/orders/in_stock_service.rb new file mode 100644 index 000000000..06ad80697 --- /dev/null +++ b/app/services/orders/in_stock_service.rb @@ -0,0 +1,23 @@ +# frozen_string_literal: true + +# Provides methods for Check if the product is in stock +class Cart::SetQuantityService + def call(order) + + return order if quantity.to_i.zero? + + raise Cart::OutStockError if quantity.to_i > orderable.stock['external'] + + item = order.order_items.find_by(orderable: orderable) + + raise ActiveRecord::RecordNotFound if item.nil? + + different_quantity = quantity.to_i - item.quantity + order.amount += (orderable.amount * different_quantity) + ActiveRecord::Base.transaction do + item.update(quantity: quantity.to_i) + order.save + end + order.reload + end +end diff --git a/app/services/orders/order_service.rb b/app/services/orders/order_service.rb new file mode 100644 index 000000000..b4febade9 --- /dev/null +++ b/app/services/orders/order_service.rb @@ -0,0 +1,18 @@ +# frozen_string_literal: true + +# Provides methods for Order +class Orders::OrderService + def in_stock?(order, stock_type = 'external') + order.order_items.each do |item| + return false if item.orderable.stock[stock_type] < item.quantity + end + true + end + + def all_products_is_active?(order) + order.order_items.each do |item| + return false unless item.orderable.is_active + end + true + end +end diff --git a/app/services/payments/payment_concern.rb b/app/services/payments/payment_concern.rb index b2fdd53d8..dc19ac078 100644 --- a/app/services/payments/payment_concern.rb +++ b/app/services/payments/payment_concern.rb @@ -18,7 +18,7 @@ module Payments::PaymentConcern def payment_success(order) ActiveRecord::Base.transaction do WalletService.debit_user_wallet(order, order.statistic_profile.user) - order.update(payment_state: 'paid') + order.update(state: 'in_progress', payment_state: 'paid') order.order_items.each do |item| ProductService.update_stock(item.orderable, 'external', 'sold', -item.quantity) end diff --git a/app/services/payments/payzen_service.rb b/app/services/payments/payzen_service.rb index 8a64cdbf0..d45a59ae4 100644 --- a/app/services/payments/payzen_service.rb +++ b/app/services/payments/payzen_service.rb @@ -11,6 +11,8 @@ class Payments::PayzenService def payment(order) amount = debit_amount(order) + raise Cart::ZeroPriceError if amount.zero? + id = PayZen::Helper.generate_ref(order, order.statistic_profile.user.id) client = PayZen::Charge.new diff --git a/app/services/payments/stripe_service.rb b/app/services/payments/stripe_service.rb index 76d307c51..35c30a02d 100644 --- a/app/services/payments/stripe_service.rb +++ b/app/services/payments/stripe_service.rb @@ -7,6 +7,9 @@ class Payments::StripeService def payment(order, payment_id) amount = debit_amount(order) + + raise Cart::ZeroPriceError if amount.zero? + # Create the PaymentIntent intent = Stripe::PaymentIntent.create( {