# MollieBank Module module MollieBank # The Sinatra Application class Application < Sinatra::Base register Sinatra::MultiRoute set :static, true set :public_folder, File.expand_path('..', __FILE__) set :views, File.expand_path('../views/', __FILE__) set :haml, { :format => :html5 } set :storage, MollieBank::Storage def self.get_or_post(path, opts={}, &block) get(path, opts, &block) post(path, opts, &block) end # Displays a information page of the Mollie-Bank gem get '/' do haml :info end # Displays a bank page for finishing the transaction get '/ideal' do transaction_id = params[:transaction_id] description = params[:description] reporturl = params[:reporturl] returnurl = params[:returnurl] amount = params[:amount] if transaction_id.nil? or description.nil? or reporturl.nil? or returnurl.nil? or amount.nil? haml :html_error, :locals => { :message => "To few params have been supplied (expected to retrieve 'transaction_id', 'description', 'reporturl', 'returnurl' and 'amount')" } else cent_amount = amount int, frac = ("%.2f" % (amount.to_f/100)).split('.') amount = "#{int},#{frac}" transaction = settings.storage.get(transaction_id) transaction[:reporturl] = reporturl transaction[:returnurl] = returnurl transaction[:amount] = cent_amount settings.storage.set(transaction_id, transaction) url_path = request.url.split('/ideal?transaction_id=')[0] haml :bank_page, :locals => { :transaction_id => transaction_id, :amount => amount, :reporturl => reporturl, :returnurl => returnurl, :description => description, :url_path => url_path } end end # Background page that sends the paid = true or paid = false to the report url get '/payment' do transaction_id = params[:transaction_id] paid = params[:paid] == "true" ? true : false if transaction_id.nil? or paid.nil? haml :html_error, :locals => { :message => "To few params have been supplied" } else transaction = settings.storage.get(transaction_id) reporturl = transaction[:reporturl] returnurl = transaction[:returnurl] transaction[:paid] = paid settings.storage.set(transaction_id, transaction) begin reporturl = URI("#{reporturl}?transaction_id=#{transaction_id}") Net::HTTP.get(reporturl) rescue end redirect_url = "#{returnurl}&transaction_id=#{transaction_id}" # if return url already contains a '?' we have to append the transaction_id with a '&' redirect_url = "#{returnurl}?transaction_id=#{transaction_id}" if returnurl.split('?').count == 1 redirect redirect_url end end # Displays the xml depending on the specified action # # @example # # returns a list of banks # http://localhost:4567/xml/ideal?a=banklist # # @example # # creates a new order # http://localhost:4567/xml/ideal?a=fetch # # @example # # checks if a order was paid # http://localhost:4567/xml/ideal?a=check get_or_post '/xml/ideal', '/xml/ideal/' do content_type 'text/xml' case params[:a] when "banklist" haml :banklist, :layout => false when "fetch" return error(-2) unless params.has_key?("partnerid") return error(-7) unless params.has_key?("description") return error(-3) unless params.has_key?("reporturl") return error(-12) unless params.has_key?("returnurl") return error(-4) unless params.has_key?("amount") return error(-14) unless params[:amount].to_i > 118 return error(-6) unless params.has_key?("bank_id") description = params[:description] reporturl = params[:reporturl] returnurl = params[:returnurl] amount = params[:amount] transaction_id = UUID.new.generate.gsub('-', '') settings.storage.set(transaction_id, {:paid => false}) #url_path = request.url.split('/xml/ideal')[0] url_path = "http://#{request.host}:#{Sinatra::Application.port}" haml :fetch, :layout => false, :locals => { :transaction_id => transaction_id, :amount => amount, :reporturl => reporturl, :returnurl => returnurl, :description => description, :url_path => url_path } when "check" return error(-11) unless params.has_key?("partnerid") return error(-8) unless params.has_key?("transaction_id") transaction_id = params[:transaction_id] transaction = settings.storage.get(transaction_id) return error(-10) if transaction.nil? is_paid = transaction[:paid] amount = transaction[:amount] transaction[:paid] = false settings.storage.set(transaction_id, transaction) haml :check, :layout => false, :locals => { :transaction_id => transaction_id, :amount => amount, :is_paid => is_paid } else error(-1) end end # Render the XML error for a specific code # # @param [int] code def error(code) # Mollie codes taken from https://www.mollie.nl/support/documentatie/betaaldiensten/ideal/en/ errors = [] errors[1] = "Did not receive a proper input value." errors[2] = "A fetch was issued without specification of 'partnerid'." errors[3] = "A fetch was issued without (proper) specification of 'reporturl'." errors[4] = "A fetch was issued without specification of 'amount'." errors[5] = "A fetch was issued without specification of 'bank_id'." errors[6] = "A fetch was issues without specification of a known 'bank_id'." errors[7] = "A fetch was issued without specification of 'description'." errors[8] = "A check was issued without specification of transaction_id." errors[9] = "Transaction_id contains illegal characters. (Logged as attempt to mangle)." errors[10] = "This is an unknown order." errors[11] = "A check was issued without specification of your partner_id." errors[12] = "A fetch was issued without (proper) specification of 'returnurl'." errors[13] = "This amount is only permitted when iDEAL contract is signed and sent to Mollie." errors[14] = "Minimum amount for an ideal transaction is 1,18 EUR." errors[15] = "A fetch was issued for an account which is not allowed to accept iDEAL payments (yet)." errors[16] = "A fetch was issued for an unknown or inactive profile." haml :error, :layout => false, :locals => { :type => "error", :code => code, :message => errors[code*-1] } end end end