Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP -- stripe checkout & wechatpay #1

Open
wants to merge 1 commit into
base: staging
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ HOSTNAME=localhost:3000
# Generate them here https://dashboard.stripe.com/account/apikeys
STRIPE_PUBLIC_KEY=pk_test_zq022DcopypastatXAVMaOJT
STRIPE_PRIVATE_KEY=sk_test_35SiP3qovcopypastaLguIyY
# Stripe webhook secret
# Use the Stripe CLI and `stripe listen --forward-to localhost:3000/stripe_webhook` to configure this in development.
# For production configuration, go to https://dashboard.stripe.com/webhooks
STRIPE_WEBHOOK_ENDPOINT_SECRET=whsec_HcopypastaS7IH3D779S
# https://stripe.com/docs/currencies
STRIPE_CURRENCY=NZD

Expand Down
132 changes: 0 additions & 132 deletions app/commands/money/charge_customer.rb

This file was deleted.

134 changes: 134 additions & 0 deletions app/commands/money/start_stripe_checkout.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,134 @@
# frozen_string_literal: true

# Copyright 2019 Matthew B. Gray
# Copyright 2019 AJ Esler
# Copyright 2021 DisCon III
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Money::StartStripeCheckout creates a pending charge record against a User for the Stripe integrations
# and sets them up to check out with Stripe.
# Truthy returns mean the user can be safely sent on to the checkout flow, otherwise check #errors for failure details.
class Money::StartStripeCheckout
attr_reader :reservation, :user, :charge_amount, :charge, :amount_owed, :success_url, :cancel_url

def initialize(reservation:, user:, amount_owed:, success_url:, cancel_url:, charge_amount: nil)
@reservation = reservation
@user = user
@charge_amount = charge_amount || amount_owed
@amount_owed = amount_owed
@success_url = success_url
@cancel_url = cancel_url
end

def call
setup_stripe_customer

check_charge_amount unless errors.any?
create_checkout_session unless errors.any?

charge_state_params = if errors.any?
{
state: ::Charge::STATE_FAILED,
comment: error_message,
}
else
{
state: ::Charge::STATE_PENDING,
comment: "Pending stripe payment",
}
end

@charge = ::Charge.stripe.create!({
user: user,
reservation: reservation,
stripe_id: @checkout_session.id,
amount: charge_amount,
}.merge(charge_state_params))

checkout_url.present?
end

def error_message
errors.to_sentence
end

def errors
@errors ||= []
end

def checkout_url
@checkout_session['url']
end

private

def check_charge_amount
if !charge_amount.present?
errors << "charge amount is missing"
end
if charge_amount <= 0
errors << "amount must be more than 0 cents"
end
if charge_amount > amount_owed
errors << "refusing to overpay for reservation"
end
end

def create_checkout_session
@checkout_session = Stripe::Checkout::Session.create({
line_items: [
{
currency: ENV.fetch('STRIPE_CURRENCY'),
amount: charge_amount.cents,
name: reservation.membership.to_s,
quantity: 1,
},
],
payment_method_types: [
'card',
'wechat_pay',
],
payment_method_options: {
wechat_pay: {
client: 'web',
}
},
mode: 'payment',
customer: user.stripe_id,
success_url: success_url,
cancel_url: cancel_url,
})
end

def setup_stripe_customer
if !user.stripe_id.present?
stripe_customer = Stripe::Customer.create(email: user.email)
user.update!(stripe_id: stripe_customer.id)
end
rescue Stripe::StripeError => e
errors << e.message.to_s
@charge.stripe_response = json_to_hash(e.response)
@charge.comment = "Failed to setup customer - #{e.message}"
end

def json_to_hash(obj)
JSON.parse(obj.to_json)
rescue
{}
end

def fully_paid?
@charge.successful? && (amount_owed - charge_amount) <= 0
end
end
54 changes: 54 additions & 0 deletions app/commands/money/stripe_checkout_failed.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# frozen_string_literal: true

# Copyright 2021 DisCon III
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

# Money::StripeCheckoutFailed updates the Charge record associated with that checkout session to indicate that the payment failed.
# Truthy returns mean that everything updated correctly, otherwise check #errors for failure details.
class Money::StripeCheckoutFailed
attr_reader :charge, :stripe_checkout_session

def initialize(charge:, stripe_checkout_session:)
@charge = charge
@stripe_checkout_session = stripe_checkout_session
end

def call
reservation = charge.reservation
reservation.transaction do
charge.state = ::Charge::STATE_FAILED
charge.stripe_response = json_to_hash(stripe_checkout_session)
charge.comment = "Stripe checkout failed."
charge.save!
end

return charge
end

def error_message
errors.to_sentence
end

def errors
@errors ||= []
end

private

def json_to_hash(obj)
JSON.parse(obj.to_json)
rescue
{}
end
end
Loading