-
Notifications
You must be signed in to change notification settings - Fork 266
super rough around the edges api for better spree paypal express #168
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
base: 2-4-stable
Are you sure you want to change the base?
Changes from 1 commit
2adc3a7
60ab41b
2135c6c
f6f3b16
806cc8f
96de768
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,202 @@ | ||
| module Spree | ||
| module Api | ||
| class PaypalController < Spree::Api::BaseController | ||
| ssl_allowed | ||
|
|
||
| def express | ||
|
|
||
| order = current_order || raise(ActiveRecord::RecordNotFound) | ||
| items = order.line_items.map(&method(:line_item)) | ||
|
|
||
| tax_adjustments = order.all_adjustments.tax.additional | ||
| shipping_adjustments = order.all_adjustments.shipping | ||
|
|
||
| order.all_adjustments.eligible.each do |adjustment| | ||
| next if (tax_adjustments + shipping_adjustments).include?(adjustment) | ||
| items << { | ||
| :Name => adjustment.label, | ||
| :Quantity => 1, | ||
| :Amount => { | ||
| :currencyID => order.currency, | ||
| :value => adjustment.amount | ||
| } | ||
| } | ||
| end | ||
|
|
||
| # Because PayPal doesn't accept $0 items at all. | ||
| # See #10 | ||
| # https://cms.paypal.com/uk/cgi-bin/?cmd=_render-content&content_ID=developer/e_howto_api_ECCustomizing | ||
| # "It can be a positive or negative value but not zero." | ||
| items.reject! do |item| | ||
| item[:Amount][:value].zero? | ||
| end | ||
| pp_request = provider.build_set_express_checkout(express_checkout_request_details(order, items)) | ||
|
|
||
| # Trying to conform to https://guides.spreecommerce.com/api/summary.html | ||
| # as much as possible | ||
| begin | ||
| pp_response = provider.set_express_checkout(pp_request) | ||
| if pp_response.success? | ||
| url = provider.express_checkout_url(pp_response, :useraction => 'commit') | ||
|
|
||
| response = Spree::Paypal.new | ||
| response.redirect_url = url | ||
| respond_with response | ||
| else | ||
| # this one is easy we can just respond with pp_response errors | ||
| render json: {errors:pp_response.errors.collect(&:long_message).join(" ")}, status: 500 | ||
| end | ||
| rescue SocketError | ||
| render json: {errors:[Spree.t('flash.connection_failed', :scope => 'paypal')]}, status: 500 | ||
| end | ||
| end | ||
|
|
||
| def confirm | ||
| order = current_order || raise(ActiveRecord::RecordNotFound) | ||
| order.payments.create!({ | ||
| :source => Spree::PaypalExpressCheckout.create({ | ||
| :token => params[:token], | ||
| :payer_id => params[:PayerID] | ||
| }), | ||
| :amount => order.total, | ||
| :payment_method => payment_method | ||
| }) | ||
|
|
||
| # using code from regular controller as psuedocode comment for what you are need to do on frontend now | ||
| # | ||
| # order.next # move order to next state | ||
| # | ||
| # if order.complete? | ||
| # flash.notice = Spree.t(:order_processed_successfully) | ||
| # redirect_to completion_route(order) | ||
| # else | ||
| # redirect_to checkout_state_path(order.state) | ||
| # end | ||
| respond_with order | ||
| end | ||
|
|
||
| def cancel | ||
| # unneeded in api version where paypal calls back to client first | ||
| # you can just do this client side | ||
| # | ||
| # flash[:notice] = Spree.t('flash.cancel', :scope => 'paypal') | ||
| # order = current_order || raise(ActiveRecord::RecordNotFound) | ||
| # redirect_to checkout_state_path(order.state, paypal_cancel_token: params[:token]) | ||
|
|
||
| render status: 200 | ||
| end | ||
|
|
||
| private | ||
|
|
||
| def current_order | ||
| @order = Spree::Order.find_by(number: order_id) | ||
| end | ||
|
|
||
| def line_item(item) | ||
| { | ||
| :Name => item.product.name, | ||
| :Number => item.variant.sku, | ||
| :Quantity => item.quantity, | ||
| :Amount => { | ||
| :currencyID => item.order.currency, | ||
| :value => item.price | ||
| }, | ||
| :ItemCategory => "Physical" | ||
| } | ||
| end | ||
|
|
||
| def express_checkout_request_details order, items | ||
| { :SetExpressCheckoutRequestDetails => { | ||
| :InvoiceID => order.number, | ||
| :BuyerEmail => order.email, | ||
| # Here we tell paypal redirect to client and have the client post back status to rails server | ||
| :ReturnURL => params[:confirm_url], | ||
| :CancelURL => params[:cancel_url], | ||
| :SolutionType => payment_method.preferred_solution.present? ? payment_method.preferred_solution : "Mark", | ||
| :LandingPage => payment_method.preferred_landing_page.present? ? payment_method.preferred_landing_page : "Billing", | ||
| :cppheaderimage => payment_method.preferred_logourl.present? ? payment_method.preferred_logourl : "", | ||
| :NoShipping => 1, | ||
| :PaymentDetails => [payment_details(items)] | ||
| }} | ||
| end | ||
|
|
||
|
|
||
| def payment_method | ||
| Spree::PaymentMethod.find(params[:payment_method_id]) | ||
| end | ||
|
|
||
| def provider | ||
| payment_method.provider | ||
| end | ||
|
|
||
| def payment_details items | ||
| # This retrieves the cost of shipping after promotions are applied | ||
| # For example, if shippng costs $10, and is free with a promotion, shipment_sum is now $10 | ||
| shipment_sum = current_order.shipments.map(&:discounted_cost).sum | ||
|
|
||
| # This calculates the item sum based upon what is in the order total, but not for shipping | ||
| # or tax. This is the easiest way to determine what the items should cost, as that | ||
| # functionality doesn't currently exist in Spree core | ||
| item_sum = current_order.total - shipment_sum - current_order.additional_tax_total | ||
|
|
||
| if item_sum.zero? | ||
| # Paypal does not support no items or a zero dollar ItemTotal | ||
| # This results in the order summary being simply "Current purchase" | ||
| { | ||
| :OrderTotal => { | ||
| :currencyID => current_order.currency, | ||
| :value => current_order.total | ||
| } | ||
| } | ||
| else | ||
| { | ||
| :OrderTotal => { | ||
| :currencyID => current_order.currency, | ||
| :value => current_order.total | ||
| }, | ||
| :ItemTotal => { | ||
| :currencyID => current_order.currency, | ||
| :value => item_sum | ||
| }, | ||
| :ShippingTotal => { | ||
| :currencyID => current_order.currency, | ||
| :value => shipment_sum, | ||
| }, | ||
| :TaxTotal => { | ||
| :currencyID => current_order.currency, | ||
| :value => current_order.additional_tax_total | ||
| }, | ||
| :ShipToAddress => address_options, | ||
| :PaymentDetailsItem => items, | ||
| :ShippingMethod => "Shipping Method Name Goes Here", | ||
| :PaymentAction => "Sale" | ||
| } | ||
| end | ||
| end | ||
|
|
||
| def address_options | ||
| return {} unless address_required? | ||
|
|
||
| address_to_bill = current_order.bill_address || current_order.ship_address | ||
| { | ||
| :Name => address_to_bill.try(:full_name), | ||
| :Street1 => address_to_bill.address1, | ||
| :Street2 => address_to_bill.address2, | ||
| :CityName => address_to_bill.city, | ||
| :Phone => address_to_bill.phone, | ||
| :StateOrProvince => address_to_bill.state_text, | ||
| :Country => address_to_bill.country.iso, | ||
| :PostalCode => address_to_bill.zipcode | ||
| } | ||
| end | ||
|
|
||
| def completion_route(order) | ||
| order_path(order, :token => order.guest_token) | ||
| end | ||
|
|
||
| def address_required? | ||
| payment_method.preferred_solution.eql?('Sole') | ||
| end | ||
| end | ||
| end | ||
| end | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| module Spree | ||
| class Paypal | ||
| include ActiveModel::SerializerSupport | ||
|
|
||
| ## simple poro to make serializing easy | ||
| # http://blog.honeybadger.io/poro-plain-old-ruby-object-tests-and-specs/ | ||
| # | ||
| # maybe this functionality should be rolled into | ||
| # the paypal express checkout object or be called paypal express idk | ||
| # | ||
| attr_accessor :redirect_url | ||
| end | ||
| end |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -15,4 +15,12 @@ | |
| end | ||
| end | ||
| end | ||
| end | ||
|
|
||
| namespace :api do | ||
| post '/paypal', :to => "paypal#express", :as => :paypal_express_api | ||
| post '/paypal/confirm', :to => "paypal#confirm", :as => :confirm_paypal_api | ||
| post '/paypal/cancel', :to => "paypal#cancel", :as => :cancel_paypal_api | ||
| get '/paypal/notify', :to => "paypal#notify", :as => :notify_paypal_api | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't see a method that handles this route.
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. there isnt one I just copied that from the the other paypal stuff I think it was some old thing that never got removed. I would search the history of the repository for it |
||
| end | ||
|
|
||
| end | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm getting an error here on line 45:
Via a console app
Error log:
Error log from my custom web app (called similarly):
Am I missing something?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very strange. In my app it just picks a layout for the json. Doesn't have anything about the view it uses in the log.
It looks like your app is not understanding to render the json even though spree's api at least purports to do that here
https://github.com/spree/spree/blob/2-4-stable/api/lib/spree/api/controller_setup.rb
so I guess I need to wrap those
render :jsoncalls inrespond_toblocks alahttp://stackoverflow.com/questions/22943892/actioncontrollerunknownformat/22944769#22944769
and/or
add
:defaults => { :format => 'json' }http://stackoverflow.com/questions/22943892/actioncontrollerunknownformat/28750863#28750863
to those api route definitions
Edit:
on second thought yeah thats almost certainly whats going on @MisinformedDNA .
I bet your
client.postcall is not properly setting a json mime type so the rails server can't figure out how to respond to itThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
My test is to simply alter the spree_api_examples to include the PayPal API. I've never had a problem with this setup in accessing any other API.
Can you run walkthrough-paypal.rb against your instance and see how it goes?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't even get the regular walkthrough running my friend
https://github.com/spree-contrib/spree_api_examples/blob/master/examples/checkout/walkthrough.rb
opened and issue with one of the many issues I'm running into
spree-contrib/spree_api_examples#5
the routes never seem to exist no matter how I try to change them to
which branch of that repo are your running @MisinformedDNA ?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm running 2-4-stable, 2.4.8.beta.
To run the api examples, just set up a clean sandbox. Alternately, you'd have to alter the baseUrl and all the calls since its not mounted at root.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Co-worker figured out the problem. We need a RABL file. See Infigic@60ab41b.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah yeah the app im working with sets up json responses differently.