From 00b09ac0fbf01be9cf63cd2ded550b3ebc9996ce Mon Sep 17 00:00:00 2001 From: Will Bradley Date: Tue, 30 Apr 2013 02:42:53 -0700 Subject: [PATCH] Finished creating sample app --- .gitignore | 2 + app/controllers/payments_controller.rb | 229 ++++++++++++++++++++----- app/models/payment.rb | 1 + app/views/payments/new.html.erb | 21 ++- app/views/payments/show.html.erb | 14 ++ config/initializers/paypal.rb | 2 + config/paypal.yml | 24 --- config/paypal.yml.dist | 24 +++ config/routes.rb | 1 + db/schema.rb | 22 +++ 10 files changed, 276 insertions(+), 64 deletions(-) create mode 100644 config/initializers/paypal.rb delete mode 100644 config/paypal.yml create mode 100644 config/paypal.yml.dist create mode 100644 db/schema.rb diff --git a/.gitignore b/.gitignore index eb3489a..ad989df 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ # Ignore all logfiles and tempfiles. /log/*.log /tmp + +paypal.yml # contains sensitive passwords diff --git a/app/controllers/payments_controller.rb b/app/controllers/payments_controller.rb index 995ff6a..b2c1247 100644 --- a/app/controllers/payments_controller.rb +++ b/app/controllers/payments_controller.rb @@ -15,9 +15,67 @@ class PaymentsController < ApplicationController def show @payment = Payment.find(params[:id]) + paypal = Paypal.new(APP_CONFIG['username'],APP_CONFIG['password'],APP_CONFIG['signature'],APP_CONFIG['url'].to_sym) + @paypal_result = paypal.do_get_recurring_payments_profile_details(@payment.profile, {}) + + Rails.logger.debug "PROFILE DETAILS:"+@paypal_result.inspect + + # {"PROFILEID"=>"I-C07L0WXLH25Y", + # "STATUS"=>"Active" + # "AUTOBILLOUTAMT"=>"NoAutoBill" + # "DESC"=>"_Why's Ruby Camping Adventures - Monthly Tips And Tricks For Camping Development" + # "MAXFAILEDPAYMENTS"=>"0" + # "SUBSCRIBERNAME"=>"Will Bradley" + # "PROFILESTARTDATE"=>"2013-05-01T07:00:00Z" + # "PROFILEREFERENCE"=>"INV20091122" + # "NEXTBILLINGDATE"=>"2013-05-01T10:00:00Z" + # "NUMCYCLESCOMPLETED"=>"0" + # "NUMCYCLESREMAINING"=>"11" + # "OUTSTANDINGBALANCE"=>"0.00" + # "FAILEDPAYMENTCOUNT"=>"0" + # "TRIALAMTPAID"=>"0.00" + # "REGULARAMTPAID"=>"0.00" + # "AGGREGATEAMT"=>"0.00" + # "AGGREGATEOPTIONALAMT"=>"0.00" + # "FINALPAYMENTDUEDATE"=>"2014-03-01T10:00:00Z" + # "TIMESTAMP"=>"2013-04-30T08:56:47Z" + # "CORRELATIONID"=>"e305cb3e7287c" + # "ACK"=>"Success" + # "VERSION"=>"74.0" + # "BUILD"=>"5650305" + # "SHIPTOSTREET"=>"1 Main St" + # "SHIPTOCITY"=>"San Jose" + # "SHIPTOSTATE"=>"CA" + # "SHIPTOZIP"=>"95131" + # "SHIPTOCOUNTRYCODE"=>"US" + # "SHIPTOCOUNTRY"=>"US" + # "SHIPTOCOUNTRYNAME"=>"United States" + # "SHIPADDRESSOWNER"=>"PayPal" + # "SHIPADDRESSSTATUS"=>"Unconfirmed" + # "BILLINGPERIOD"=>"Month" + # "BILLINGFREQUENCY"=>"1" + # "TOTALBILLINGCYCLES"=>"11" + # "CURRENCYCODE"=>"USD" + # "AMT"=>"5.00" + # "SHIPPINGAMT"=>"0.00" + # "TAXAMT"=>"0.00" + # "REGULARBILLINGPERIOD"=>"Month" + # "REGULARBILLINGFREQUENCY"=>"1" + # "REGULARTOTALBILLINGCYCLES"=>"11" + # "REGULARCURRENCYCODE"=>"USD" + # "REGULARAMT"=>"5.00" + # "REGULARSHIPPINGAMT"=>"0.00" + # "REGULARTAXAMT"=>"0.00"} + + respond_to do |format| - format.html # show.html.erb - format.json { render json: @payment } + if @paypal_result['ACK'] == 'Success' + format.html # show.html.erb + format.json { render json: @payment } + else + format.html { redirect_to payments_url, notice: 'There was a problem contacting PayPal. This issue has been logged.' } + format.json { render json: @payment.errors, status: :unprocessable_entity } + end end end @@ -26,58 +84,151 @@ class PaymentsController < ApplicationController def new @payment = Payment.new + paypal = Paypal.new(APP_CONFIG['username'],APP_CONFIG['password'],APP_CONFIG['signature'],APP_CONFIG['url'].to_sym) + + subscription_request = { + "PAYMENTACTION" => "Sale", + "L_BILLINGTYPE0" => "RecurringPayments", + "DESC" => "_Why's Ruby Camping Adventures", + "L_BILLINGAGREEMENTDESCRIPTION0" => "_Why's Ruby Camping Adventures - Monthly Tips And Tricks For Camping Development" + } + + response = paypal.set_express_checkout( + return_url='http://localhost:3000/payments/confirmed', + cancel_url='http://localhost:3000/payments/aborted', + amount='5.00', + currency='USD', + other_params=subscription_request) + + Rails.logger.debug "SETEXPRESSCHECKOUT:"+response.inspect + + @token = (response.ack == 'Success') ? response['TOKEN'] : '' + respond_to do |format| - format.html # new.html.erb - format.json { render json: @payment } + if response['ACK'] == 'Success' + format.html # new.html.erb + format.json { render json: @payment } + else + Rails.logger.warn "SETEXPRESSCHECKOUT ERROR:"+response.inspect + format.html { redirect_to payments_url, notice: 'There was a problem contacting PayPal. This issue has been logged.' } + format.json { render json: @payment.errors, status: :unprocessable_entity } + end + end + end + + def confirmed + token = params[:token] + + paypal = Paypal.new(APP_CONFIG['username'],APP_CONFIG['password'],APP_CONFIG['signature'],APP_CONFIG['url'].to_sym) + + response = paypal.do_get_express_checkout_details(token) + + error = false + + if response['ACK'] != 'Success' + Rails.logger.warn "GETEXPRESSCHECKOUT ERROR:"+response.inspect + error = true + else + Rails.logger.debug "GETEXPRESSCHECKOUT:"+response.inspect + + response = paypal.do_express_checkout_payment(token=token, + payment_action='Sale', + payer_id=response['PAYERID'], + amount='5.00') + #transaction_id = response['TRANSACTIONID'] + + if response['ACK'] != 'Success' + Rails.logger.warn "DOEXPESSCHECKOUT ERROR:"+response.inspect + error = true + else + Rails.logger.debug "DOEXPESSCHECKOUT:"+response.inspect + + response = paypal.do_create_recurring_payments_profile(token, + start_date=(Time.parse(response['TIMESTAMP']) + 1.minute).iso8601, # Start date has to be in the future according to PayPal + profile_reference='INV20091122', + description="_Why's Ruby Camping Adventures - Monthly Tips And Tricks For Camping Development", + billing_period='Month', + billing_frequency=1, + total_billing_cycles=nil, # nil/0 = infinite + amount='5.00', + currency='USD') + + if response['ACK'] != 'Success' + Rails.logger.warn "CREATERECURRINGPAYMENT ERROR:"+response.inspect + error = true + else + Rails.logger.debug "CREATERECURRINGPAYMENT:"+response.inspect + + profile_id = response['PROFILEID'] + + @payment = Payment.new({profile: profile_id}) + + unless @payment.save + Rails.logger.warn "Payment Save ERROR:"+response.inspect + error = true + end + end + end + end + + respond_to do |format| + unless error + format.html { redirect_to payments_url, notice: 'Payment was successfully created.' } + format.json { render json: @payment, status: :created, location: @payment } + else + @payment.errors.add_to_base "There was a problem processing your subscription. This issue has been logged." + format.html { redirect_to payments_url } + format.json { render json: @payment.errors, status: :unprocessable_entity } + end end end # GET /payments/1/edit - def edit - @payment = Payment.find(params[:id]) - end + # def edit + # @payment = Payment.find(params[:id]) + # end # POST /payments # POST /payments.json - def create - @payment = Payment.new(params[:payment]) + # def create + # @payment = Payment.new(params[:payment]) - respond_to do |format| - if @payment.save - format.html { redirect_to @payment, notice: 'Payment was successfully created.' } - format.json { render json: @payment, status: :created, location: @payment } - else - format.html { render action: "new" } - format.json { render json: @payment.errors, status: :unprocessable_entity } - end - end - end + # respond_to do |format| + # if @payment.save + # format.html { redirect_to @payment, notice: 'Payment was successfully created.' } + # format.json { render json: @payment, status: :created, location: @payment } + # else + # format.html { render action: "new" } + # format.json { render json: @payment.errors, status: :unprocessable_entity } + # end + # end + # end # PUT /payments/1 # PUT /payments/1.json - def update - @payment = Payment.find(params[:id]) + # def update + # @payment = Payment.find(params[:id]) - respond_to do |format| - if @payment.update_attributes(params[:payment]) - format.html { redirect_to @payment, notice: 'Payment was successfully updated.' } - format.json { head :no_content } - else - format.html { render action: "edit" } - format.json { render json: @payment.errors, status: :unprocessable_entity } - end - end - end + # respond_to do |format| + # if @payment.update_attributes(params[:payment]) + # format.html { redirect_to @payment, notice: 'Payment was successfully updated.' } + # format.json { head :no_content } + # else + # format.html { render action: "edit" } + # format.json { render json: @payment.errors, status: :unprocessable_entity } + # end + # end + # end # DELETE /payments/1 # DELETE /payments/1.json - def destroy - @payment = Payment.find(params[:id]) - @payment.destroy + # def destroy + # @payment = Payment.find(params[:id]) + # @payment.destroy - respond_to do |format| - format.html { redirect_to payments_url } - format.json { head :no_content } - end - end + # respond_to do |format| + # format.html { redirect_to payments_url } + # format.json { head :no_content } + # end + # end end diff --git a/app/models/payment.rb b/app/models/payment.rb index 2c43fd0..ed0fe8c 100644 --- a/app/models/payment.rb +++ b/app/models/payment.rb @@ -1,3 +1,4 @@ class Payment < ActiveRecord::Base attr_accessible :profile + validates_presence_of :profile end diff --git a/app/views/payments/new.html.erb b/app/views/payments/new.html.erb index d96c87c..a42f46f 100644 --- a/app/views/payments/new.html.erb +++ b/app/views/payments/new.html.erb @@ -1,5 +1,24 @@

New payment

-<%= render 'form' %> +<% if @payment.errors.any? %> +
+

<%= pluralize(@payment.errors.count, "error") %> prohibited this payment from being saved:

+ + +
+ <% end %> + +<%= form_tag('https://www.sandbox.paypal.com/cgi-bin/webscr', {:method => 'post', :authenticity_token => false } ) do %> + + <%= hidden_field_tag 'cmd', "_express-checkout" %> + + <%= hidden_field_tag 'token', @token %> + + <%= submit_tag 'Subscribe Via PayPal', {:id => 'submit_subscription_request', :name => 'submit'} %> +<% end %> <%= link_to 'Back', payments_path %> diff --git a/app/views/payments/show.html.erb b/app/views/payments/show.html.erb index cbbf163..da2fb20 100644 --- a/app/views/payments/show.html.erb +++ b/app/views/payments/show.html.erb @@ -4,6 +4,20 @@ Profile: <%= @payment.profile %>

+

+ Status: <%= @paypal_result['STATUS'] %>
+ Last Payment Date: <%= @paypal_result['LASTPAYMENTDATE'] %>
+ Last Payment Amount: <%= @paypal_result['LASTPAYMENTAMT'] %> +

+

+ # Payments Complete:<%= @paypal_result['NUMCYCLESCOMPLETED'] %>
+ Start date: <%= @paypal_result['PROFILESTARTDATE'] %>
+ Next Billing date: <%= @paypal_result['NEXTBILLINGDATE'] %>
+ Total Amount paid: <%= @paypal_result['REGULARAMTPAID'] %> +

+

+ PayPal Timestamp: <%= @paypal_result['TIMESTAMP'] %> +

<%= link_to 'Edit', edit_payment_path(@payment) %> | diff --git a/config/initializers/paypal.rb b/config/initializers/paypal.rb new file mode 100644 index 0000000..9137800 --- /dev/null +++ b/config/initializers/paypal.rb @@ -0,0 +1,2 @@ +#require File.dirname(__FILE__) + '/../../config/environment.rb' +APP_CONFIG = YAML.load_file("#{Rails.root}/config/paypal.yml")[Rails.env] \ No newline at end of file diff --git a/config/paypal.yml b/config/paypal.yml deleted file mode 100644 index b616cef..0000000 --- a/config/paypal.yml +++ /dev/null @@ -1,24 +0,0 @@ - development: - username: username - password: pass - signature: sig - url: sandbox - action: https://www.sandbox.paypal.com/cgi-bin/webscr - test: - username: username - password: pass - signature: sig - url: sandbox - action: https://www.sandbox.paypal.com/cgi-bin/webscr - staging: - username: username - password: pass - signature: sig - url: sandbox - action: https://www.sandbox.paypal.com/cgi-bin/webscr - production: - username: "username" - password: "password" - signature: "signature" - url: production - action: https://wwwpaypal.com/cgi-bin/webscr diff --git a/config/paypal.yml.dist b/config/paypal.yml.dist new file mode 100644 index 0000000..617d7ab --- /dev/null +++ b/config/paypal.yml.dist @@ -0,0 +1,24 @@ +development: + username: p_api1.paypal.com + password: your_password + signature: your_signature + url: sandbox + action: https://www.sandbox.paypal.com/cgi-bin/webscr +test: + username: p_api1.paypal.com + password: your_password + signature: your_signature + url: sandbox + action: https://www.sandbox.paypal.com/cgi-bin/webscr +staging: + username: p_api1.paypal.com + password: your_password + signature: your_signature + url: sandbox + action: https://www.sandbox.paypal.com/cgi-bin/webscr +production: + username: "username" + password: "password" + signature: "signature" + url: production + action: https://wwwpaypal.com/cgi-bin/webscr diff --git a/config/routes.rb b/config/routes.rb index bef134f..789438b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,5 @@ RubyPaypalExample::Application.routes.draw do + match 'payments/confirmed' => 'payments#confirmed' resources :payments diff --git a/db/schema.rb b/db/schema.rb new file mode 100644 index 0000000..948c773 --- /dev/null +++ b/db/schema.rb @@ -0,0 +1,22 @@ +# encoding: UTF-8 +# This file is auto-generated from the current state of the database. Instead +# of editing this file, please use the migrations feature of Active Record to +# incrementally modify your database, and then regenerate this schema definition. +# +# Note that this schema.rb definition is the authoritative source for your +# database schema. If you need to create the application database on another +# system, you should be using db:schema:load, not running all the migrations +# from scratch. The latter is a flawed and unsustainable approach (the more migrations +# you'll amass, the slower it'll run and the greater likelihood for issues). +# +# It's strongly recommended to check this file into your version control system. + +ActiveRecord::Schema.define(:version => 20130430055458) do + + create_table "payments", :force => true do |t| + t.string "profile" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + +end