Skip to content

Commit

Permalink
close #238 follow order state machine for payway_v2
Browse files Browse the repository at this point in the history
  • Loading branch information
theachoem committed Jan 20, 2025
1 parent 597f4a0 commit 71de983
Show file tree
Hide file tree
Showing 23 changed files with 297 additions and 600 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@ def request_update_payment
if order.paid?
render_serialized_payload { serialize_resource(order) }
else
payment = find_payment(order, params[:payment_number])
context = payment.request_update

if context.success? && context.error_message.blank?
render_serialized_payload { serialize_resource(order) }
completer = Spree::Checkout::Complete.new.call(order: payment.order)
if completer.success?
render_serialized_payload { serialize_resource(order.reload) }
else
render_error_payload(context.error_message)
render_error_payload(completer.error)
end
end
end
Expand Down
28 changes: 5 additions & 23 deletions app/controllers/spree/webhook/payways_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,11 @@ class PaywaysController < BaseController
# match via: [:get, :post]
# {"response"=>"{\"tran_id\":\"PE13LXT1\",\"status\":0"}"}
def v2_return
handler_service = v2_request_updater_service

return_callback_handler(handler_service)
return_callback_handler
end

def return
handler_service = request_updater_service

return_callback_handler(handler_service)
return_callback_handler
end

# https://vtenh.herokuapp.com/payways/continue?tran_id=P2W2S1LB
Expand All @@ -28,29 +24,15 @@ def continue

private

def v2_request_updater_service
::Vpago::PaywayV2::PaymentRequestUpdater
end

def request_updater_service
::Vpago::Payway::PaymentRequestUpdater
end

# the callback invoke by PAYWAY in case of success
def return_callback_handler(handler_service)
# pawway send get request with nothing
def return_callback_handler
return render plain: :ok if request.method == 'GET'

builder = Vpago::PaywayReturnOptionsBuilder.new(params: params)
payment = builder.payment

request_updater = handler_service.new(payment)
request_updater.call

order = payment.order
order = order.reload
completer = Spree::Checkout::Complete.new.call(order: payment.order)

if order.paid? || payment.pending?
if completer.success?
render plain: :success
else
render plain: :failed, status: 400
Expand Down
2 changes: 1 addition & 1 deletion app/models/spree/gateway/payway.rb
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def process(_money, _source, gateway_options)
ActiveMerchant::Billing::Response.new(true, 'Order created')
end

def cancel(_response_code)
def cancel(_response_code, _payment)
# we can use this to send request to payment gateway api to cancel the payment ( void )
# currently Payway does not support to cancel the gateway

Expand Down
94 changes: 62 additions & 32 deletions app/models/spree/gateway/payway_v2.rb
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
module Spree
class Gateway::PaywayV2 < PaymentMethod
# preference :endpoint, :string
# preference :return_url, :string
# preference :continue_success_url, :string
preference :host, :string
preference :api_key, :string
preference :merchant_id, :string
Expand All @@ -12,11 +9,6 @@ class Gateway::PaywayV2 < PaymentMethod
preference :transaction_fee_percentage, :string
preference :public_key, :text

# Only enable one-click payments if spree_auth_devise is installed
# def self.allow_one_click_payments?
# Gem.loaded_specs.key?('spree_auth_devise')
# end

validates :preferred_public_key, presence: true, if: :require_public_key?

def require_public_key?
Expand All @@ -27,6 +19,7 @@ def payment_source_class
Spree::VpagoPaymentSource
end

# override
def payment_profiles_supported?
false
end
Expand All @@ -39,43 +32,80 @@ def card_type
end
end

def payment_option_card?
preferences[:payment_option] == Vpago::Payway::CARD_TYPE_CARDS
# partial to render the gateway.
def method_type
'payway_v2'
end

def payment_option_aba?
preferences[:payment_option] == Vpago::Payway::CARD_TYPE_ABAPAY
# override
# authorize payment if pre-auth is enabled, otherwise purchase / complete immediately.
def auto_capture?
!enable_pre_auth?
end

# partial to render the gateway.
def method_type
'payway_v2'
# override
def capture(_amount, _response_code, gateway_options)
_, payment_number = gateway_options[:order_id].split('-')
payment = Spree::Payment.find_by(number: payment_number)

return ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Authorization successful.') unless enable_pre_auth?

completer = Vpago::PaywayV2::PreAuthCompleter.new(payment)
completer.call

if completer.success?
ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Pre-authorization successfully captured.')
else
ActiveMerchant::Billing::Response.new(false, 'Payway Gateway: Failed to capture pre-authorization.')
end
end

# Custom PaymentMethod/Gateway can redefine this method to check method
# availability for concrete order.
def available_for_order?(_order)
true
# override
# purchase is used when pre auth disabled
def purchase(_amount, _source, _gateway_options = {})
_, payment_number = gateway_options[:order_id].split('-')
payment = Spree::Payment.find_by(number: payment_number)

check_transaction(payment)
end

# force to purchase instead of authorize
def auto_capture?
true
# override
# authorize is used when pre auth enabled
def authorize(_amount, _source, gateway_options = {})
_, payment_number = gateway_options[:order_id].split('-')
payment = Spree::Payment.find_by(number: payment_number)

check_transaction(payment)
end

def process(_money, _source, gateway_options)
Rails.logger.debug { "About to create payment for order #{gateway_options[:order_id]}" }
# First of all, invalidate all previous tranx orders to prevent multiple paid orders
# source.save!
ActiveMerchant::Billing::Response.new(true, 'Order created')
def check_transaction(payment)
checker = Vpago::PaywayV2::TransactionStatus.new(payment)
checker.call

if checker.success?
ActiveMerchant::Billing::Response.new(true, "Payway Gateway: Success #{checker.status}")
else
ActiveMerchant::Billing::Response.new(false, "Payway Gateway: Failed #{checker.error_message}", {}, { error_code: checker.status })
end
end

def cancel(_response_code)
# we can use this to send request to payment gateway api to cancel the payment ( void )
# currently Payway does not support to cancel the gateway
# override
def void(_response_code, payment)
return ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Payment has been voided.') unless enable_pre_auth?

canceler = Vpago::PaywayV2::PreAuthCanceler.new(payment)
canceler.call

if canceler.success?
ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Pre-authorization successfully canceled.')
else
ActiveMerchant::Billing::Response.new(false, 'Payway Gateway: Failed to cancel pre-authorization.')
end
end

# in our case don't do anything
ActiveMerchant::Billing::Response.new(true, 'Payway order has been cancelled.')
# override
def cancel(_response_code, _payment)
ActiveMerchant::Billing::Response.new(true, 'Payway Gateway: Payment has been canceled.')
end
end
end
4 changes: 1 addition & 3 deletions app/models/vpago/adjustment_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,4 @@ def set_handle_by
end
end

unless Spree::Adjustment.included_modules.include?(Vpago::AdjustmentDecorator)
Spree::Adjustment.prepend(Vpago::AdjustmentDecorator)
end
Spree::Adjustment.prepend(Vpago::AdjustmentDecorator) unless Spree::Adjustment.included_modules.include?(Vpago::AdjustmentDecorator)
62 changes: 3 additions & 59 deletions app/models/vpago/order_decorator.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ def self.prepended(base)
through: :line_items

base.state_machine.before_transition from: :cart, do: :ensure_valid_vendor_payment_methods
base.state_machine.after_transition to: :complete, do: :generate_line_items_total_metadata
end

def ensure_valid_vendor_payment_methods
Expand All @@ -25,38 +26,14 @@ def line_items_from_same_vendor?
line_items.joins(:variant).pluck('spree_variants.vendor_id').uniq.size == 1
end

# Make sure the order confirmation is delivered when the order has been paid for.
def finalize!
# lock all adjustments (coupon promotions, etc.)
all_adjustments.each(&:close)

# update payment and shipment(s) states, and save
updater.update_payment_state

shipments.each do |shipment|
shipment.update!(self)
shipment.finalize! if paid? || authorized?
end

updater.update_shipment_state
save!
updater.run_hooks

touch :completed_at

deliver_order_confirmation_email if !confirmation_delivered? && (paid? || authorized?)

consider_risk
end

def required_payway_payout?
line_items.any?(&:required_payway_payout?) || shipments.any?(&:required_payway_payout?)
end

# override
def available_payment_methods(store = nil)
payment_methods = if vendor_payment_methods.any?
available_vendor_payment_methods
vendor_payment_methods
else
collect_payment_methods(store)
end
Expand All @@ -68,20 +45,6 @@ def available_payment_methods(store = nil)
end
end

def available_vendor_payment_methods
if ticket_seller_user?
vendor_payment_methods \
else
vendor_payment_methods.reject { |pm| pm.type == 'Spree::PaymentMethod::Check' }
end
end

def ticket_seller_user?
return false if user.nil?

user.has_spree_role?('ticket_seller')
end

def line_items_count
line_items.size
end
Expand All @@ -90,29 +53,10 @@ def generate_line_items_total_metadata
line_items.each(&:update_total_metadata)
end

def send_confirmation_email!
return unless !confirmation_delivered? && (paid? || authorized?)

deliver_order_confirmation_email
end

def successful_payment
paid? || payments.any? { |p| p.after_pay_method? && p.authorized? }
end

alias paid_or_authorized? successful_payment

def authorized?
payments.last.authorized?
end

def order_adjustment_total
adjustments.eligible.sum(:amount)
end
end
end

if Spree::Order.included_modules.exclude?(Vpago::OrderDecorator)
Spree::Order.register_update_hook(:generate_line_items_total_metadata)
Spree::Order.prepend(Vpago::OrderDecorator)
end
Spree::Order.prepend(Vpago::OrderDecorator) if Spree::Order.included_modules.exclude?(Vpago::OrderDecorator)
48 changes: 0 additions & 48 deletions app/models/vpago/payment/vpago_payment_processing_decorator.rb

This file was deleted.

Loading

0 comments on commit 71de983

Please sign in to comment.