diff --git a/db/manifest b/db/manifest index 55ae4eae6..d48a70cc5 100755 --- a/db/manifest +++ b/db/manifest @@ -332,4 +332,5 @@ chat_channel.sql jamblaster.sql test_drive_lessons.sql whitelist.sql -teacher_student_flags.sql \ No newline at end of file +teacher_student_flags.sql +add_sale_source_col.sql diff --git a/db/up/add_sale_source_col.sql b/db/up/add_sale_source_col.sql new file mode 100644 index 000000000..5b1607e97 --- /dev/null +++ b/db/up/add_sale_source_col.sql @@ -0,0 +1 @@ +ALTER TABLE sales ADD COLUMN source VARCHAR NOT NULL DEFAULT 'recurly'; diff --git a/ruby/lib/jam_ruby/models/sale.rb b/ruby/lib/jam_ruby/models/sale.rb index 7fb4e073a..98d126c18 100644 --- a/ruby/lib/jam_ruby/models/sale.rb +++ b/ruby/lib/jam_ruby/models/sale.rb @@ -73,17 +73,53 @@ module JamRuby # if it can't validate the receipt, or communicate with Apple at all, etc # # So, if this raises exceptions, you can handle them in the stubbed out begin/rescue in ApiJamTracksController#ios_order_placed - def self.validateIOSReceipt(receipt) + def self.validateIOSReceipt(receipt, price_data) + byebug # these are all 'in cents' (as painfully named to be very clear), and all expected to be integers - price_info = {subtotal_in_cents:nil, total_in_cents:nil, tax_in_cents:nil, currency: 'USD'} + price = price_data['product_price'].to_f * 100.0 + + price_info = { + subtotal_in_cents: price, + total_in_cents: price, + tax_in_cents: nil, + currency: price_data['product_currency'] + } # communicate with Apple; populate price_info + url = 'production' != Rails.env ? "https://sandbox.itunes.apple.com/verifyReceipt" : "https://buy.itunes.apple.com/verifyReceipt" + uri = URI.parse(url) + http = Net::HTTP.new(uri.host, uri.port) + http.use_ssl = true + http.verify_mode = OpenSSL::SSL::VERIFY_NONE + request = Net::HTTP::Post.new("/v1.1/auth") + request.add_field('Content-Type', 'application/json') + request.body = { 'receipt-data' => receipt } + begin + response = http.request(request) + rescue + raise $! + end + json_resp = JSON.parse(response.body) + + # https://developer.apple.com/library/ios/releasenotes/General/ValidateAppStoreReceipt/Chapters/ReceiptFields.html#//apple_ref/doc/uid/TP40010573-CH106-SW1 + + if 0 != json_resp.status + err_msgs = { + 21000 => 'The App Store could not read the JSON object you provided.', + 21002 => 'The data in the receipt-data property was malformed or missing.', + 21003 => 'The receipt could not be authenticated.', + 21005 => 'The receipt server is not currently available.', + 21007 => 'This receipt is from the test environment, but it was sent to the production environment for verification. Send it to the test environment instead.', + 21008 => 'This receipt is from the production environment, but it was sent to the test environment for verification. Send it to the production environment instead.' + } + raise err_msgs[json_resp.status] + end price_info end - def self.ios_purchase(current_user, jam_track, receipt) + def self.ios_purchase(current_user, jam_track, receipt, price_data) jam_track_right = nil @@ -93,7 +129,7 @@ module JamRuby using_free_credit = current_user.redeem_free_credit - sale = create_jam_track_sale(current_user) + sale = create_jam_track_sale(current_user, 'ios') if sale.valid? @@ -106,7 +142,7 @@ module JamRuby sale.recurly_currency = 'USD' sale.save! else - price_info = validateIOSReceipt(receipt) + price_info = validateIOSReceipt(receipt, price_data) SaleLineItem.create_from_jam_track(current_user, sale, jam_track, using_free_credit) @@ -454,11 +490,12 @@ module JamRuby sale_type == JAMTRACK_SALE end - def self.create_jam_track_sale(user) + def self.create_jam_track_sale(user, sale_source=nil) sale = Sale.new sale.user = user sale.sale_type = JAMTRACK_SALE # gift cards and jam tracks are sold with this type of sale sale.order_total = 0 + sale.source = sale_source if sale_source sale.save sale end diff --git a/ruby/lib/jam_ruby/models/sale_receipt_ios.rb b/ruby/lib/jam_ruby/models/sale_receipt_ios.rb new file mode 100644 index 000000000..4a311dd9a --- /dev/null +++ b/ruby/lib/jam_ruby/models/sale_receipt_ios.rb @@ -0,0 +1,7 @@ +module JamRuby + class SaleReceiptIOS < JsonStore + + belongs_to :sale, class_name: "JamRuby::Sale", foreign_key: :foreign_key1_id + + end +end diff --git a/web/app/controllers/api_jam_tracks_controller.rb b/web/app/controllers/api_jam_tracks_controller.rb index 8630b44d4..46e9b6aa9 100644 --- a/web/app/controllers/api_jam_tracks_controller.rb +++ b/web/app/controllers/api_jam_tracks_controller.rb @@ -336,11 +336,14 @@ class ApiJamTracksController < ApiController end begin - Sale.ios_purchase(current_user, jam_track, nil) + Sale.ios_purchase(current_user, + jam_track, + params[:receipt], + params[:price_data]) rescue # JONATHAN - this definitely needs beefing up so that you can communicate back to the app any errors you might raise. # ... Go wild with this response; I just stubbed something. - response = {message:"Unable to complete purchase.", reason: nil} + response = { message: $!.to_s } render :json => response, :status => 422 return end diff --git a/web/lib/ios_receipt_validator.rb b/web/lib/ios_receipt_validator.rb new file mode 100644 index 000000000..159917a41 --- /dev/null +++ b/web/lib/ios_receipt_validator.rb @@ -0,0 +1,8 @@ +require 'httparty' + +class IosReceiptValidator + include HTTParty + base_uri 'production' != Rails.env ? "https://sandbox.itunes.apple.com/verifyReceipt" : "https://buy.itunes.apple.com/verifyReceipt" + default_params :output => 'json' + format :json +end