diff --git a/app/controllers/admin/paypal_payments_controller.rb b/app/controllers/admin/paypal_payments_controller.rb
index 9b1dcc5..6ae41d0 100644
--- a/app/controllers/admin/paypal_payments_controller.rb
+++ b/app/controllers/admin/paypal_payments_controller.rb
@@ -1,53 +1,43 @@
class Admin::PaypalPaymentsController < Admin::BaseController
- before_filter :load_data
- before_filter :load_amount, :except => :country_changed
resource_controller
belongs_to :order
ssl_required
- update do
- wants.html { redirect_to edit_object_url }
- end
-
- def country_changed
- end
-
- # to allow capture (NB also included in order controller...)
+ # to allow capture (NB also included in checkout controller...)
include Spree::PaypalExpress
def capture
+ load_object
if !@order.paypal_payments.empty? && (payment = @order.paypal_payments.last).can_capture?
- do_capture(payment.find_authorization)
+ paypal_capture(payment.find_authorization)
flash[:notice] = t("paypal_capture_complete")
else
flash[:error] = t("unable_to_capture_paypal")
end
- redirect_to edit_object_url
- end
+ redirect_to edit_admin_order_payment_url(@order, @paypal_payment)
+ end
- private
- def load_data
+
+ def refund
load_object
- @selected_country_id = params[:payment_presenter][:address_country_id].to_i if params.has_key?('payment_presenter')
- @selected_country_id ||= @order.bill_address.country_id if @order and @order.bill_address
- @selected_country_id ||= Spree::Config[:default_country_id]
-
- @states = State.find_all_by_country_id(@selected_country_id, :order => 'name')
- @countries = Country.find(:all)
+ if params.has_key? :amount
+
+ if !@order.paypal_payments.empty?
+ payment = @order.paypal_payments.first
+
+ paypal_refund(payment.find_capture, params[:amount].to_f)
+
+ flash[:notice] = t("paypal_refund_complete")
+ else
+ flash[:error] = t("unable_to_refund_paypal")
+ end
+ redirect_to edit_admin_order_payment_url(@order, @paypal_payment)
+
+
+ end
end
- # what for?
- def load_amount
- @amount = params[:amount] || @order.total
- end
-
- def build_object
- @object ||= end_of_association_chain.send parent? ? :build : :new, object_params
- # not relevant?
- # @object.creditcard = Creditcard.new(:address => @object.order.bill_address.clone) unless @object.creditcard
- @object
- end
-
+
end
diff --git a/app/models/paypal_payment.rb b/app/models/paypal_payment.rb
index 8491e8c..7b76c2e 100644
--- a/app/models/paypal_payment.rb
+++ b/app/models/paypal_payment.rb
@@ -3,15 +3,21 @@ class PaypalPayment < Payment
alias :txns :paypal_txns
- # def find_authorization
- # #find the transaction associated with the original authorization/capture
- # txns.find(:first,
- # :conditions => ["txn_type = ? AND response_code IS NOT NULL", CreditcardTxn::TxnType::AUTHORIZE],
- # :order => 'created_at DESC')
- # end
+ def find_authorization
+ #find the transaction associated with the original authorization/capture
+ txns.find(:first,
+ :conditions => {:pending_reason => "authorization", :payment_status => "Pending"},
+ :order => 'created_at DESC')
+ end
- def can_capture? # push to parent? perhaps not
- true
- #txns.last == find_authorization
+ def find_capture
+ #find the transaction associated with the original authorization/capture
+ txns.find(:first,
+ :conditions => {:payment_status => "Completed"},
+ :order => 'created_at DESC')
+ end
+
+ def can_capture?
+ find_capture.nil?
end
end
diff --git a/app/views/admin/payments/edit.html.erb b/app/views/admin/payments/edit.html.erb
new file mode 100644
index 0000000..8c0b7cc
--- /dev/null
+++ b/app/views/admin/payments/edit.html.erb
@@ -0,0 +1,121 @@
+<%= render :partial => 'admin/shared/order_tabs', :locals => {:current => "Payments"} %>
+
+
<%= t("activerecord.models.#{@object.class.to_s.underscore}.one") %>
+
+<%=error_messages_for :creditcard_payment %>
+<% form_for(object, :url => object_url, :html => { :method => :put}) do |payment_form| %>
+<%= hidden_field_tag :payment_type, object.class.to_s.underscore %>
+
+
+
+ <%= object.amount %>
+
+
+ <% if object.class == CreditcardPayment %>
+
+ <% end %>
+
+ <% if object.class == PaypalPayment %>
+
+ <% end %>
+
+
+ <%= button t('continue') %>
+
+
+<% end %>
+
+<%#= link_to t("capture").titleize, capture_admin_order_payment_url(@order, @creditcard_payment), :confirm => t('are_you_sure_you_want_to_capture') if object.can_capture? %>
+
diff --git a/app/views/admin/paypal_payments/edit.html.erb b/app/views/admin/paypal_payments/edit.html.erb
deleted file mode 100644
index 72d73cd..0000000
--- a/app/views/admin/paypal_payments/edit.html.erb
+++ /dev/null
@@ -1,33 +0,0 @@
-<%= render :partial => 'admin/shared/order_tabs', :locals => {:current => "Payments"} %>
-
-<%= t("paypal_payment")%>
-
-<%= t("paypal_txn_id")%>: #<%= @paypal_payment.creditcard.display_number %>
-
-<%=error_messages_for :paypal_payment %>
-
-<% form_for(@paypal_payment, :url => object_url, :html => { :method => :put}) do |payment_form| %>
-
-
- <%= t("transaction") %> |
- <%= t("amount") %> |
- <%= t("response_code") %> |
- <%= "#{t('spree.date')}/#{t('spree.time')}" %> |
-
- <% @paypal_payment.txns.each do |t| %>
-
- <%=CreditcardTxn::TxnType.from_value t.txn_type.to_i%> |
- <%=number_to_currency t.amount%> |
- <%=t.response_code%> |
- <%=t.created_at.to_s(:date_time24)%> |
-
- <% end %>
-
-
-
- <%= button t('update') %>
-
-
-<% end %>
-<%= link_to t("capture").titleize, capture_admin_order_paypal_payment_url(@order, @paypal_payment), :confirm => t('are_you_sure_you_want_to_capture') if @paypal_payment.can_capture? %>
-<%= link_to t("list"), collection_url %>
diff --git a/app/views/admin/paypal_payments/new.html.erb b/app/views/admin/paypal_payments/new.html.erb
deleted file mode 100644
index cdd55e5..0000000
--- a/app/views/admin/paypal_payments/new.html.erb
+++ /dev/null
@@ -1,15 +0,0 @@
-<%= render :partial => 'admin/shared/order_tabs', :locals => {:current => "Payments"} %>
-
-<%= t("new_credit_card_payment")%>
-
-<%=error_messages_for :creditcard_payment %>
-<% form_for @creditcard_payment, :url => collection_url do |payment_form| %>
- <%= t("billing_address")%>
- <% payment_form.fields_for :creditcard do |creditcard_form| %>
- <%= render :partial => 'admin/shared/form_address', :locals => {:f => creditcard_form} %>
- <% end %>
-
- <%= button t('continue') %>
- <%= t("or") %> <%= link_to t("actions.cancel"), admin_order_payments_url(@order) %>
-
-<% end %>
diff --git a/app/views/admin/paypal_payments/refund.html.erb b/app/views/admin/paypal_payments/refund.html.erb
new file mode 100644
index 0000000..b9ff81b
--- /dev/null
+++ b/app/views/admin/paypal_payments/refund.html.erb
@@ -0,0 +1,15 @@
+<%= render :partial => 'admin/shared/order_tabs', :locals => {:current => "Payments"} %>
+
+<% form_tag do %>
+
+ <%= t('refund') %>
+
+<% end %>
diff --git a/config/locales/en-GB.yml b/config/locales/en-GB.yml
index 98f8c2c..6a26e1d 100644
--- a/config/locales/en-GB.yml
+++ b/config/locales/en-GB.yml
@@ -6,4 +6,15 @@ en-GB:
paypal_capture_complete: Paypal Transaction has been captured.
unable_to_capture_paypal: Unable to capture Paypal Transaction.
signature: Signature
-
+ order_not_yet_placed: "Your order has not been be placed, please review the details and click Confirm below to finalise your order."
+ paypal_payment_id: PayPal Payment ID
+ pending_reason: Pending Reason
+ result: Result
+ activerecord:
+ attributes:
+ paypal_payment:
+ amount: Amount
+ models:
+ paypal_payment:
+ one: PayPal Payment
+ other: PayPal Payments
\ No newline at end of file
diff --git a/config/locales/en-US.yml b/config/locales/en-US.yml
index 8f6c01a..5186ff3 100644
--- a/config/locales/en-US.yml
+++ b/config/locales/en-US.yml
@@ -7,3 +7,14 @@ en-US:
unable_to_capture_paypal: Unable to capture Paypal Transaction.
signature: Signature
order_not_yet_placed: "Your order has not been be placed, please review the details and click Confirm below to finalise your order."
+ paypal_payment_id: PayPal Payment ID
+ pending_reason: Pending Reason
+ result: Result
+ activerecord:
+ attributes:
+ paypal_payment:
+ amount: Amount
+ models:
+ paypal_payment:
+ one: PayPal Payment
+ other: PayPal Payments
diff --git a/config/routes.rb b/config/routes.rb
index e569894..e6b349d 100644
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -8,7 +8,7 @@ map.resources :paypal_express_callbacks, :only => [:index]
map.namespace :admin do |admin|
admin.resources :orders do |order|
- order.resources :paypal_payments, :member => {:capture => :get}, :has_many => [:paypal_payments]
+ order.resources :paypal_payments, :member => {:capture => :get, :refund => :any}, :has_many => [:txns]
end
end
diff --git a/db/migrate/20100128115525_add_transaction_id_to_ppx_txn.rb b/db/migrate/20100128115525_add_transaction_id_to_ppx_txn.rb
new file mode 100644
index 0000000..c14caa4
--- /dev/null
+++ b/db/migrate/20100128115525_add_transaction_id_to_ppx_txn.rb
@@ -0,0 +1,9 @@
+class AddTransactionIdToPpxTxn < ActiveRecord::Migration
+ def self.up
+ add_column :paypal_txns, :transaction_id, :string
+ end
+
+ def self.down
+ remove_column :paypal_txns, :transaction_id
+ end
+end
\ No newline at end of file
diff --git a/lib/spree/paypal_express.rb b/lib/spree/paypal_express.rb
index 966ad91..107072c 100644
--- a/lib/spree/paypal_express.rb
+++ b/lib/spree/paypal_express.rb
@@ -42,36 +42,39 @@ module Spree::PaypalExpress
gateway = paypal_gateway
@ppx_details = gateway.details_for params[:token]
- gateway_error(@ppx_details) unless @ppx_details.success?
- # now save the updated order info
- @order.checkout.email = @ppx_details.email
- @order.checkout.special_instructions = @ppx_details.params["note"]
+ if @ppx_details.success?
+ # now save the updated order info
+ @order.checkout.email = @ppx_details.email
+ @order.checkout.special_instructions = @ppx_details.params["note"]
- @order.update_attribute(:user, current_user)
+ @order.update_attribute(:user, current_user)
- ship_address = @ppx_details.address
- order_ship_address = Address.new :firstname => @ppx_details.params["first_name"],
- :lastname => @ppx_details.params["last_name"],
- :address1 => ship_address["address1"],
- :address2 => ship_address["address2"],
- :city => ship_address["city"],
- :country => Country.find_by_iso(ship_address["country"]),
- :zipcode => ship_address["zip"],
- # phone is currently blanked in AM's PPX response lib
- :phone => @ppx_details.params["phone"] || "(not given)"
+ ship_address = @ppx_details.address
+ order_ship_address = Address.new :firstname => @ppx_details.params["first_name"],
+ :lastname => @ppx_details.params["last_name"],
+ :address1 => ship_address["address1"],
+ :address2 => ship_address["address2"],
+ :city => ship_address["city"],
+ :country => Country.find_by_iso(ship_address["country"]),
+ :zipcode => ship_address["zip"],
+ # phone is currently blanked in AM's PPX response lib
+ :phone => @ppx_details.params["phone"] || "(not given)"
- if (state = State.find_by_abbr(ship_address["state"]))
- order_ship_address.state = state
+ if (state = State.find_by_abbr(ship_address["state"]))
+ order_ship_address.state = state
+ else
+ order_ship_address.state_name = ship_address["state"]
+ end
+
+ order_ship_address.save!
+
+ @order.checkout.ship_address = order_ship_address
+ @order.checkout.save
+ render :partial => "shared/paypal_express_confirm", :layout => true
else
- order_ship_address.state_name = ship_address["state"]
+ gateway_error(@ppx_details)
end
-
- order_ship_address.save!
-
- @order.checkout.ship_address = order_ship_address
- @order.checkout.save
- render :partial => "shared/paypal_express_confirm", :layout => true
end
def paypal_finish
@@ -87,52 +90,98 @@ module Spree::PaypalExpress
ppx_auth_response = gateway.authorize((@order.total*100).to_i, opts)
end
- gateway_error(ppx_auth_response) unless ppx_auth_response.success?
+ if ppx_auth_response.success?
- payment = @order.paypal_payments.create(:amount => ppx_auth_response.params["gross_amount"].to_f)
+ payment = @order.paypal_payments.create(:amount => ppx_auth_response.params["gross_amount"].to_f)
- transaction = PaypalTxn.new(:paypal_payment => payment,
- :gross_amount => ppx_auth_response.params["gross_amount"].to_f,
- :message => ppx_auth_response.params["message "],
- :payment_status => ppx_auth_response.params["payment_status"],
- :pending_reason => ppx_auth_response.params["pending_reason"],
- :transaction_type => ppx_auth_response.params["transaction_type"],
- :payment_type => ppx_auth_response.params["payment_type"],
- :ack => ppx_auth_response.params["ack"],
- :token => ppx_auth_response.params["token"],
- :avs_response => ppx_auth_response.avs_result["code"],
- :cvv_response => ppx_auth_response.cvv_result["code"])
+ transaction = PaypalTxn.new(:paypal_payment => payment,
+ :gross_amount => ppx_auth_response.params["gross_amount"].to_f,
+ :message => ppx_auth_response.params["message"],
+ :payment_status => ppx_auth_response.params["payment_status"],
+ :pending_reason => ppx_auth_response.params["pending_reason"],
+ :transaction_id => ppx_auth_response.params["transaction_id"],
+ :transaction_type => ppx_auth_response.params["transaction_type"],
+ :payment_type => ppx_auth_response.params["payment_type"],
+ :ack => ppx_auth_response.params["ack"],
+ :token => ppx_auth_response.params["token"],
+ :avs_response => ppx_auth_response.avs_result["code"],
+ :cvv_response => ppx_auth_response.cvv_result["code"])
- payment.paypal_txns << transaction
+ payment.paypal_txns << transaction
- @order.save!
- @checkout.reload
- until @checkout.state == "complete"
- @checkout.next!
+ @order.save!
+ @checkout.reload
+ until @checkout.state == "complete"
+ @checkout.next!
+ end
+
+ # todo - share code
+ flash[:notice] = t('order_processed_successfully')
+ order_params = {:checkout_complete => true}
+ order_params[:order_token] = @order.token unless @order.user
+ session[:order_id] = nil if @order.checkout.completed_at
+
+ else
+ order_params = {}
+ gateway_error(ppx_auth_response)
end
- # todo - share code
- flash[:notice] = t('order_processed_successfully')
- order_params = {:checkout_complete => true}
- order_params[:order_token] = @order.token unless @order.user
- session[:order_id] = nil if @order.checkout.completed_at
redirect_to order_url(@order, order_params)
end
- # def do_capture(authorization)
- # response = paypal_gateway.capture((100 * authorization.amount).to_i, authorization.response_code)
- #
- # gateway_error(response) unless response.success?
- #
- # # TODO needs to be cleaned up or recast...
- # payment = PaypalPayment.find(authorization.creditcard_payment_id)
- #
- # # create a transaction to reflect the capture
- # payment.txns << CreditcardTxn.new( :amount => authorization.amount,
- # :response_code => response.authorization,
- # :txn_type => CreditcardTxn::TxnType::CAPTURE )
- # payment.save
- # end
+ def paypal_capture(authorization)
+ ppx_response = paypal_gateway.capture((100 * authorization.gross_amount).to_i, authorization.transaction_id)
+
+ if ppx_response.success?
+ payment = authorization.paypal_payment
+
+ transaction = PaypalTxn.new(:paypal_payment => payment,
+ :gross_amount => ppx_response.params["gross_amount"].to_f,
+ :message => ppx_response.params["message"],
+ :payment_status => ppx_response.params["payment_status"],
+ :pending_reason => ppx_response.params["pending_reason"],
+ :transaction_id => ppx_response.params["transaction_id"],
+ :transaction_type => ppx_response.params["transaction_type"],
+ :payment_type => ppx_response.params["payment_type"],
+ :ack => ppx_response.params["ack"],
+ :token => ppx_response.params["token"],
+ :avs_response => ppx_response.avs_result["code"],
+ :cvv_response => ppx_response.cvv_result["code"])
+
+ payment.paypal_txns << transaction
+
+ payment.save
+ else
+ gateway_error(ppx_response)
+ end
+ end
+
+ def paypal_refund(authorization, amount=nil)
+ ppx_response = paypal_gateway.credit(amount.nil? ? (100 * authorization.gross_amount).to_i : (100 * amount).to_i, authorization.transaction_id)
+
+ if ppx_response.success?
+ payment = authorization.paypal_payment
+
+ transaction = PaypalTxn.new(:paypal_payment => payment,
+ :gross_amount => ppx_response.params["gross_refund_amount"].to_f,
+ :message => ppx_response.params["message"],
+ :payment_status => "Refunded",
+ :pending_reason => ppx_response.params["pending_reason"],
+ :transaction_id => ppx_response.params["refund_transaction_id"],
+ :transaction_type => ppx_response.params["transaction_type"],
+ :payment_type => ppx_response.params["payment_type"],
+ :ack => ppx_response.params["ack"],
+ :token => ppx_response.params["token"],
+ :avs_response => ppx_response.avs_result["code"],
+ :cvv_response => ppx_response.cvv_result["code"])
+
+ payment.paypal_txns << transaction
+
+ payment.save
+ else
+ gateway_error(ppx_response)
+ end
+ end
private
def fixed_opts
@@ -288,8 +337,6 @@ module Spree::PaypalExpress
integration = BillingIntegration.find(params[:integration_id]) if params.key? :integration_id
integration ||= BillingIntegration.current
-
-
gateway = integration.provider
end
end