From ec4cf4dea9c88a7805afb274324ad46a84798c31 Mon Sep 17 00:00:00 2001 From: Will Bradley Date: Sat, 24 Aug 2013 02:18:37 -0700 Subject: [PATCH] Adding IPNs --- Gemfile | 2 +- Gemfile.lock | 8 ++ app/assets/javascripts/ipn.js.coffee | 3 + app/assets/stylesheets/ipn.css.scss | 3 + app/controllers/ipns_controller.rb | 34 +++++ app/helpers/ipn_helper.rb | 2 + app/models/ipn.rb | 50 +++++++ app/models/payment.rb | 6 +- app/models/user.rb | 4 + app/views/ipns/index.html.erb | 26 ++++ app/views/ipns/new.html.erb | 123 ++++++++++++++++++ app/views/ipns/show.html.erb | 17 +++ app/views/payments/_form.html.erb | 4 + app/views/payments/index.html.erb | 2 + app/views/payments/show.html.erb | 19 ++- config/routes.rb | 2 + db/migrate/20130824062334_create_ipns.rb | 24 ++++ .../20130824072157_add_amount_to_payments.rb | 5 + db/schema.rb | 25 +++- test/fixtures/ipns.yml | 7 + test/functional/ipn_controller_test.rb | 7 + test/unit/helpers/ipn_helper_test.rb | 4 + test/unit/ipn_test.rb | 7 + 23 files changed, 379 insertions(+), 5 deletions(-) create mode 100644 app/assets/javascripts/ipn.js.coffee create mode 100644 app/assets/stylesheets/ipn.css.scss create mode 100644 app/controllers/ipns_controller.rb create mode 100644 app/helpers/ipn_helper.rb create mode 100644 app/models/ipn.rb create mode 100644 app/views/ipns/index.html.erb create mode 100644 app/views/ipns/new.html.erb create mode 100644 app/views/ipns/show.html.erb create mode 100644 db/migrate/20130824062334_create_ipns.rb create mode 100644 db/migrate/20130824072157_add_amount_to_payments.rb create mode 100644 test/fixtures/ipns.yml create mode 100644 test/functional/ipn_controller_test.rb create mode 100644 test/unit/helpers/ipn_helper_test.rb create mode 100644 test/unit/ipn_test.rb diff --git a/Gemfile b/Gemfile index 8ecbde8..6b59f1b 100644 --- a/Gemfile +++ b/Gemfile @@ -40,7 +40,7 @@ gem 'bcrypt-ruby', '~> 3.0.0' # gem 'capistrano' # To use debugger -# gem 'ruby-debug' +gem 'debugger' #gem "paperclip", "~> 3.0" gem 'gravtastic' diff --git a/Gemfile.lock b/Gemfile.lock index 94abf55..d3be24e 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -39,6 +39,13 @@ GEM coffee-script-source execjs coffee-script-source (1.3.3) + columnize (0.3.6) + debugger (1.6.0) + columnize (>= 0.3.1) + debugger-linecache (~> 1.2.0) + debugger-ruby_core_source (~> 1.2.1) + debugger-linecache (1.2.0) + debugger-ruby_core_source (1.2.2) devise (2.1.1) bcrypt-ruby (~> 3.0) orm_adapter (~> 0.1) @@ -120,6 +127,7 @@ DEPENDENCIES bcrypt-ruby (~> 3.0.0) cancan coffee-rails (~> 3.2.1) + debugger devise gravtastic jquery-rails diff --git a/app/assets/javascripts/ipn.js.coffee b/app/assets/javascripts/ipn.js.coffee new file mode 100644 index 0000000..7615679 --- /dev/null +++ b/app/assets/javascripts/ipn.js.coffee @@ -0,0 +1,3 @@ +# Place all the behaviors and hooks related to the matching controller here. +# All this logic will automatically be available in application.js. +# You can use CoffeeScript in this file: http://jashkenas.github.com/coffee-script/ diff --git a/app/assets/stylesheets/ipn.css.scss b/app/assets/stylesheets/ipn.css.scss new file mode 100644 index 0000000..ee38bc7 --- /dev/null +++ b/app/assets/stylesheets/ipn.css.scss @@ -0,0 +1,3 @@ +// Place all the styles related to the Ipn controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ diff --git a/app/controllers/ipns_controller.rb b/app/controllers/ipns_controller.rb new file mode 100644 index 0000000..a392dd8 --- /dev/null +++ b/app/controllers/ipns_controller.rb @@ -0,0 +1,34 @@ +class IpnsController < ApplicationController + load_and_authorize_resource :ipn, :except => "create" + before_filter :authenticate_user! + + protect_from_forgery :except => [:create] + + def index + @ipns = Ipn.all + end + + def show + end + + def new + end + + def create + #TODO: ensure the request is actually from paypal + @ipn = Ipn.new_from_dynamic_params(params) + @ipn.data = params.to_json + @ipn.save + render :nothing => true + end + + def link + result = @ipn.link_payment + if result.first + redirect_to ipns_url, :notice => 'Payment was successfully linked.' + else + redirect_to ipns_url, :notice => result.last + end + end + +end \ No newline at end of file diff --git a/app/helpers/ipn_helper.rb b/app/helpers/ipn_helper.rb new file mode 100644 index 0000000..a56c555 --- /dev/null +++ b/app/helpers/ipn_helper.rb @@ -0,0 +1,2 @@ +module IpnHelper +end diff --git a/app/models/ipn.rb b/app/models/ipn.rb new file mode 100644 index 0000000..3643066 --- /dev/null +++ b/app/models/ipn.rb @@ -0,0 +1,50 @@ +class Ipn < ActiveRecord::Base + attr_accessible :data + belongs_to :payment + + after_create :create_payment + + def self.new_from_dynamic_params(params) + ipn = Ipn.new() + + ipn.attributes.each do |c| + unless params[c.first.to_sym].nil? + ipn[c.first.to_sym] = params[c.first.to_sym] + end + end + + return ipn + end + + def link_payment + create_payment + end + + private + def create_payment + # find user by email, then by payee + user = User.find_by_email(self.payer_email) + user = User.find_by_payee(self.payer_email) if user.nil? && self.payer_email.present? + + # Only create payments if the amount matches a member level + if user.present? + if User.member_levels[self.payment_gross.to_i].present? + payment = Payment.new + payment.date = self.payment_date + payment.user_id = user.id + payment.amount = self.payment_gross + if payment.save + self.payment_id = payment.id + self.save! + else + return [false, "Unable to link payment. Payment error: #{payment.errors.full_messages.first}"] + end + else + return [false, "Unable to link payment. Couldn't find membership level '#{self.payment_gross.to_i}'."] + end + else + return [false, "Unable to link payment. Couldn't find user/payee '#{self.payer_email}'."] + end + end + +end diff --git a/app/models/payment.rb b/app/models/payment.rb index ef9d681..ea70430 100644 --- a/app/models/payment.rb +++ b/app/models/payment.rb @@ -1,10 +1,12 @@ class Payment < ActiveRecord::Base belongs_to :user - attr_accessible :date, :user_id, :created_by + has_one :ipn + attr_accessible :date, :user_id, :created_by, :amount - validates_presence_of :user_id, :date, :created_by + validates_presence_of :user_id, :date, :amount # not created_by validates_uniqueness_of :date, :scope => :user_id, :message => ' of payment already exists for this user.' + def human_date if date.year < DateTime.now.year date.strftime("%b %e, %y") diff --git a/app/models/user.rb b/app/models/user.rb index 512a0aa..00890e3 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -85,6 +85,10 @@ class User < ActiveRecord::Base end end + def self.member_levels + {25 => "Associate", 50 => "Basic", 100 => "Plus"} + end + def member_status case self.member_level.to_i when 0 diff --git a/app/views/ipns/index.html.erb b/app/views/ipns/index.html.erb new file mode 100644 index 0000000..9a6afff --- /dev/null +++ b/app/views/ipns/index.html.erb @@ -0,0 +1,26 @@ + + + + + + + + + <% @ipns.reverse!.each do |ipn| %> + + + + + + + + + <% end %> +
DateNameItemAmount
<%= ipn.payment_date %><%= ipn.first_name %> <%= ipn.last_name %><%= ipn.item_name %><%= ipn.payment_gross %> + <% if ipn.payment.present? %> + <%= link_to "Linked Payment", ipn.payment %> + <% else %> + <%= link_to "Try to link email '#{ipn.payer_email}' at membership level '#{ipn.payment_gross.to_i}'", link_ipn_path(ipn) %> + <% end %> + <%= link_to "Details", ipn %>
+ diff --git a/app/views/ipns/new.html.erb b/app/views/ipns/new.html.erb new file mode 100644 index 0000000..3322347 --- /dev/null +++ b/app/views/ipns/new.html.erb @@ -0,0 +1,123 @@ + <%= form_tag('/ipns') do |f| %> + + + +
+ <%= submit_tag %> +
+
+ <%= label_tag :first_name %> + <%= text_field_tag :first_name, "John" %> +
+
+ <%= label_tag :last_name %> + <%= text_field_tag :last_name, "Smith" %> +
+
+ <%= label_tag :payer_email %> + <%= text_field_tag :payer_email, "jsmith@example.com" %> +
+
+ <%= label_tag :item_name %> + <%= text_field_tag :item_name, "Associate Membership" %> +
+
+ <%= label_tag :payment_gross %> + <%= text_field_tag :payment_gross, "25.00" %> +
+
+ <%= label_tag :transaction_subject %> + <%= text_field_tag :transaction_subject, "" %> +
+
+ <%= label_tag :payment_date %> + <%= text_field_tag :payment_date, Date.today.to_s %> +
+
+ <%= label_tag :txn_type %> + <%= text_field_tag :txn_type, "subscr_payment" %> +
+
+ <%= label_tag :subscr_id %> + <%= text_field_tag :subscr_id, "I-1234567890" %> +
+
+ <%= label_tag :residence_country %> + <%= text_field_tag :residence_country, "US" %> +
+
+ <%= label_tag :mc_currency %> + <%= text_field_tag :mc_currency, "USD" %> +
+
+ <%= label_tag :business %> + <%= text_field_tag :business, "hslfinances@gmail.com" %> +
+
+ <%= label_tag :payment_type %> + <%= text_field_tag :payment_type, "instant" %> +
+
+ <%= label_tag :protection_eligibility %> + <%= text_field_tag :protection_eligibility, "Ineligible" %> +
+
+ <%= label_tag :verify_sign %> + <%= text_field_tag :verify_sign, "12ru9021j9f21j90fj1290fj2910fj0219fj0" %> +
+
+ <%= label_tag :payer_status %> + <%= text_field_tag :payer_status, "verified" %> +
+
+ <%= label_tag :txn_id %> + <%= text_field_tag :txn_id, "1234567890" %> +
+
+ <%= label_tag :receiver_email %> + <%= text_field_tag :receiver_email, "hslfinances@gmail.com" %> +
+
+ <%= label_tag :payer_id %> + <%= text_field_tag :payer_id, "V812314914" %> +
+
+ <%= label_tag :receiver_id %> + <%= text_field_tag :receiver_id, "V90R1280182" %> +
+
+ <%= label_tag :payment_status %> + <%= text_field_tag :payment_status, "Completed" %> +
+
+ <%= label_tag :payment_fee %> + <%= text_field_tag :payment_fee, "0.85" %> +
+
+ <%= label_tag :mc_fee %> + <%= text_field_tag :mc_fee, "0.85" %> +
+
+ <%= label_tag :mc_gross %> + <%= text_field_tag :mc_gross, "25.00" %> +
+
+ <%= label_tag :charset %> + <%= text_field_tag :charset, "windows-1252" %> +
+
+ <%= label_tag :notify_version %> + <%= text_field_tag :notify_version, "3.7" %> +
+
+ <%= label_tag :ipn_track_id %> + <%= text_field_tag :ipn_track_id, "9d3d032d9070" %> +
+
+ <%= submit_tag %> +
+ <% end %> \ No newline at end of file diff --git a/app/views/ipns/show.html.erb b/app/views/ipns/show.html.erb new file mode 100644 index 0000000..8fdc7ec --- /dev/null +++ b/app/views/ipns/show.html.erb @@ -0,0 +1,17 @@ +

IPN Details

+ +<% @ipn.attributes.except("data","payment_id").each do |attr| %> +

+ <%= attr.first.to_s %>: + <%= @ipn.attributes[attr.first] %> +

+<% end %> +

+ <% if @ipn.payment.present? %> + <%= link_to "Payment", @ipn.payment %> + <% else %> + Couldn't link '<%= @ipn.payer_email %>' or payment amount '<%= @ipn.payment_gross.to_i %>' not a valid membership level. Please create payment manually. + <% end %> +

+ +<%= link_to "Back", ipns_path %> \ No newline at end of file diff --git a/app/views/payments/_form.html.erb b/app/views/payments/_form.html.erb index dd04aad..72043e4 100644 --- a/app/views/payments/_form.html.erb +++ b/app/views/payments/_form.html.erb @@ -19,6 +19,10 @@ <%= f.label :date, "Paid for month beginning" %>
<%= f.date_select :date, :default => (DateTime.now - 1.month) %> +
+ <%= f.label :amount %>
+ <%= f.number_field :amount %> +
<%= f.submit %>
diff --git a/app/views/payments/index.html.erb b/app/views/payments/index.html.erb index 9be4eff..58bbd83 100644 --- a/app/views/payments/index.html.erb +++ b/app/views/payments/index.html.erb @@ -6,6 +6,7 @@ User Paid for month
beginning + Amount @@ -15,6 +16,7 @@ <%= link_to payment.user.name_with_payee_and_member_level, payment.user unless payment.user.blank? %> <%= payment.human_date %> + <%= payment.amount %> <%= link_to 'Details', payment %> <%= link_to 'Edit', edit_payment_path(payment) %> diff --git a/app/views/payments/show.html.erb b/app/views/payments/show.html.erb index 59906ce..c735823 100644 --- a/app/views/payments/show.html.erb +++ b/app/views/payments/show.html.erb @@ -8,9 +8,19 @@ <%= @payment.date %>

+

+ Amount: + <%= @payment.amount %> +

+

Last Modified by: - <%= user = @users.find{|u| u.id == @payment.created_by}; link_to user.name, user unless user.blank? %> + <% user = @users.find{|u| u.id == @payment.created_by} %> + <% if user.blank? %> + n/a + <% else %> + <%= link_to user.name, user %> + <% end %>

@@ -23,6 +33,13 @@ <%= @payment.updated_at %>

+<% if @payment.ipn.present? %> +

+ <%= link_to "Paid via PayPal", @payment.ipn %> +

+<% end %> + + <%= link_to 'Edit', edit_payment_path(@payment) %> | <%= link_to 'Destroy', @payment, :confirm => 'Are you sure you want to destroy this payment?', :method => :delete if can? :destroy, @payment %> | diff --git a/config/routes.rb b/config/routes.rb index 518a30a..6c64774 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -1,4 +1,6 @@ Dooraccess::Application.routes.draw do + resources :ipns + match 'ipns/:id/link' => 'ipns#link', :as => :link_ipn resources :payments diff --git a/db/migrate/20130824062334_create_ipns.rb b/db/migrate/20130824062334_create_ipns.rb new file mode 100644 index 0000000..fad43b4 --- /dev/null +++ b/db/migrate/20130824062334_create_ipns.rb @@ -0,0 +1,24 @@ +class CreateIpns < ActiveRecord::Migration + def change + create_table :ipns do |t| + t.integer :payment_id + t.text :data + t.string :txn_id + t.string :txn_type + t.string :first_name + t.string :last_name + t.string :payer_business_name + t.string :payer_email + t.string :payer_id + t.string :auth_amount + t.string :payment_date + t.string :payment_fee + t.string :payment_gross + t.string :payment_status + t.string :item_name + t.string :payment_type + + t.timestamps + end + end +end diff --git a/db/migrate/20130824072157_add_amount_to_payments.rb b/db/migrate/20130824072157_add_amount_to_payments.rb new file mode 100644 index 0000000..37b65e6 --- /dev/null +++ b/db/migrate/20130824072157_add_amount_to_payments.rb @@ -0,0 +1,5 @@ +class AddAmountToPayments < ActiveRecord::Migration + def change + add_column :payments, :amount, :decimal + end +end diff --git a/db/schema.rb b/db/schema.rb index 19fced1..915b9a5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -1,3 +1,4 @@ +# 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. @@ -10,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20130212083412) do +ActiveRecord::Schema.define(:version => 20130824072157) do create_table "cards", :force => true do |t| t.string "card_number" @@ -35,6 +36,27 @@ ActiveRecord::Schema.define(:version => 20130212083412) do t.datetime "updated_at", :null => false end + create_table "ipns", :force => true do |t| + t.integer "payment_id" + t.text "data" + t.string "txn_id" + t.string "txn_type" + t.string "first_name" + t.string "last_name" + t.string "payer_business_name" + t.string "payer_email" + t.string "payer_id" + t.string "auth_amount" + t.string "payment_date" + t.string "payment_fee" + t.string "payment_gross" + t.string "payment_status" + t.string "item_name" + t.string "payment_type" + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + create_table "mac_logs", :force => true do |t| t.string "mac" t.string "ip" @@ -64,6 +86,7 @@ ActiveRecord::Schema.define(:version => 20130212083412) do t.datetime "created_at", :null => false t.datetime "updated_at", :null => false t.integer "created_by" + t.decimal "amount" end add_index "payments", ["user_id"], :name => "index_payments_on_user_id" diff --git a/test/fixtures/ipns.yml b/test/fixtures/ipns.yml new file mode 100644 index 0000000..6d2f6e4 --- /dev/null +++ b/test/fixtures/ipns.yml @@ -0,0 +1,7 @@ +# Read about fixtures at http://api.rubyonrails.org/classes/ActiveRecord/Fixtures.html + +one: + data: MyText + +two: + data: MyText diff --git a/test/functional/ipn_controller_test.rb b/test/functional/ipn_controller_test.rb new file mode 100644 index 0000000..0d5ac04 --- /dev/null +++ b/test/functional/ipn_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class IpnControllerTest < ActionController::TestCase + # test "the truth" do + # assert true + # end +end diff --git a/test/unit/helpers/ipn_helper_test.rb b/test/unit/helpers/ipn_helper_test.rb new file mode 100644 index 0000000..be0cbae --- /dev/null +++ b/test/unit/helpers/ipn_helper_test.rb @@ -0,0 +1,4 @@ +require 'test_helper' + +class IpnHelperTest < ActionView::TestCase +end diff --git a/test/unit/ipn_test.rb b/test/unit/ipn_test.rb new file mode 100644 index 0000000..fbdc7fa --- /dev/null +++ b/test/unit/ipn_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class IpnTest < ActiveSupport::TestCase + # test "the truth" do + # assert true + # end +end