offsite_payments 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/MIT-LICENSE +20 -0
- data/README.md +70 -0
- data/lib/offsite_payments.rb +46 -0
- data/lib/offsite_payments/action_view_helper.rb +72 -0
- data/lib/offsite_payments/helper.rb +119 -0
- data/lib/offsite_payments/integrations.rb +14 -0
- data/lib/offsite_payments/integrations/a1agregator.rb +245 -0
- data/lib/offsite_payments/integrations/authorize_net_sim.rb +580 -0
- data/lib/offsite_payments/integrations/bit_pay.rb +150 -0
- data/lib/offsite_payments/integrations/bogus.rb +32 -0
- data/lib/offsite_payments/integrations/chronopay.rb +283 -0
- data/lib/offsite_payments/integrations/citrus.rb +227 -0
- data/lib/offsite_payments/integrations/direc_pay.rb +339 -0
- data/lib/offsite_payments/integrations/directebanking.rb +237 -0
- data/lib/offsite_payments/integrations/doku.rb +171 -0
- data/lib/offsite_payments/integrations/dotpay.rb +166 -0
- data/lib/offsite_payments/integrations/dwolla.rb +160 -0
- data/lib/offsite_payments/integrations/e_payment_plans.rb +146 -0
- data/lib/offsite_payments/integrations/easy_pay.rb +137 -0
- data/lib/offsite_payments/integrations/epay.rb +161 -0
- data/lib/offsite_payments/integrations/first_data.rb +133 -0
- data/lib/offsite_payments/integrations/gestpay.rb +201 -0
- data/lib/offsite_payments/integrations/hi_trust.rb +179 -0
- data/lib/offsite_payments/integrations/ipay88.rb +240 -0
- data/lib/offsite_payments/integrations/klarna.rb +291 -0
- data/lib/offsite_payments/integrations/liqpay.rb +216 -0
- data/lib/offsite_payments/integrations/maksuturva.rb +231 -0
- data/lib/offsite_payments/integrations/mollie_ideal.rb +213 -0
- data/lib/offsite_payments/integrations/moneybookers.rb +199 -0
- data/lib/offsite_payments/integrations/nochex.rb +228 -0
- data/lib/offsite_payments/integrations/pag_seguro.rb +255 -0
- data/lib/offsite_payments/integrations/paxum.rb +114 -0
- data/lib/offsite_payments/integrations/pay_fast.rb +269 -0
- data/lib/offsite_payments/integrations/paydollar.rb +142 -0
- data/lib/offsite_payments/integrations/payflow_link.rb +194 -0
- data/lib/offsite_payments/integrations/paypal.rb +362 -0
- data/lib/offsite_payments/integrations/paypal_payments_advanced.rb +23 -0
- data/lib/offsite_payments/integrations/paysbuy.rb +71 -0
- data/lib/offsite_payments/integrations/payu_in.rb +266 -0
- data/lib/offsite_payments/integrations/payu_in_paisa.rb +46 -0
- data/lib/offsite_payments/integrations/platron.rb +153 -0
- data/lib/offsite_payments/integrations/pxpay.rb +271 -0
- data/lib/offsite_payments/integrations/quickpay.rb +232 -0
- data/lib/offsite_payments/integrations/rbkmoney.rb +110 -0
- data/lib/offsite_payments/integrations/robokassa.rb +154 -0
- data/lib/offsite_payments/integrations/sage_pay_form.rb +425 -0
- data/lib/offsite_payments/integrations/two_checkout.rb +332 -0
- data/lib/offsite_payments/integrations/universal.rb +180 -0
- data/lib/offsite_payments/integrations/valitor.rb +200 -0
- data/lib/offsite_payments/integrations/verkkomaksut.rb +143 -0
- data/lib/offsite_payments/integrations/web_pay.rb +186 -0
- data/lib/offsite_payments/integrations/webmoney.rb +119 -0
- data/lib/offsite_payments/integrations/wirecard_checkout_page.rb +359 -0
- data/lib/offsite_payments/integrations/world_pay.rb +273 -0
- data/lib/offsite_payments/notification.rb +71 -0
- data/lib/offsite_payments/return.rb +37 -0
- data/lib/offsite_payments/version.rb +3 -0
- metadata +270 -0
| @@ -0,0 +1,216 @@ | |
| 1 | 
            +
            module OffsitePayments #:nodoc:
         | 
| 2 | 
            +
              module Integrations #:nodoc:
         | 
| 3 | 
            +
                # Documentation: https://www.liqpay.com/?do=pages&p=cnb10
         | 
| 4 | 
            +
                module Liqpay
         | 
| 5 | 
            +
                  mattr_accessor :service_url
         | 
| 6 | 
            +
                  self.service_url = 'https://liqpay.com/?do=clickNbuy'
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                  mattr_accessor :signature_parameter_name
         | 
| 9 | 
            +
                  self.signature_parameter_name = 'signature'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def self.helper(order, account, options = {})
         | 
| 12 | 
            +
                    Helper.new(order, account, options)
         | 
| 13 | 
            +
                  end
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  def self.notification(query_string, options = {})
         | 
| 16 | 
            +
                    Notification.new(query_string, options)
         | 
| 17 | 
            +
                  end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                  def self.return(query_string)
         | 
| 20 | 
            +
                    Return.new(query_string)
         | 
| 21 | 
            +
                  end
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  class Helper < OffsitePayments::Helper
         | 
| 24 | 
            +
                    def initialize(order, account, options = {})
         | 
| 25 | 
            +
                      @secret = options.delete(:secret)
         | 
| 26 | 
            +
                      super
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                      add_field 'version', '1.2'
         | 
| 29 | 
            +
                    end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                    def form_fields
         | 
| 32 | 
            +
                      xml = "<request>
         | 
| 33 | 
            +
                        <version>1.2</version>
         | 
| 34 | 
            +
                        <result_url>#{@fields["result_url"]}</result_url>
         | 
| 35 | 
            +
                        <server_url>#{@fields["server_url"]}</server_url>
         | 
| 36 | 
            +
                        <merchant_id>#{@fields["merchant_id"]}</merchant_id>
         | 
| 37 | 
            +
                        <order_id>#{@fields["order_id"]}</order_id>
         | 
| 38 | 
            +
                        <amount>#{@fields["amount"]}</amount>
         | 
| 39 | 
            +
                        <currency>#{@fields["currency"]}</currency>
         | 
| 40 | 
            +
                        <description>#{@fields["description"]}</description>
         | 
| 41 | 
            +
                        <default_phone>#{@fields["default_phone"]}</default_phone>
         | 
| 42 | 
            +
                        <pay_way>card</pay_way>
         | 
| 43 | 
            +
                        </request>".strip
         | 
| 44 | 
            +
                      sign = Base64.encode64(Digest::SHA1.digest("#{@secret}#{xml}#{@secret}")).strip
         | 
| 45 | 
            +
                      {"operation_xml" => Base64.encode64(xml), "signature" => sign}
         | 
| 46 | 
            +
                    end
         | 
| 47 | 
            +
             | 
| 48 | 
            +
                    mapping :account, 'merchant_id'
         | 
| 49 | 
            +
                    mapping :amount, 'amount'
         | 
| 50 | 
            +
                    mapping :currency, 'currency'
         | 
| 51 | 
            +
                    mapping :order, 'order_id'
         | 
| 52 | 
            +
                    mapping :description, 'description'
         | 
| 53 | 
            +
                    mapping :phone, 'default_phone'
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                    mapping :notify_url, 'server_url'
         | 
| 56 | 
            +
                    mapping :return_url, 'result_url'
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  class Notification < OffsitePayments::Notification
         | 
| 60 | 
            +
                    def self.recognizes?(params)
         | 
| 61 | 
            +
                      params.has_key?('amount') && params.has_key?('order_id')
         | 
| 62 | 
            +
                    end
         | 
| 63 | 
            +
             | 
| 64 | 
            +
                    def initialize(post, options = {})
         | 
| 65 | 
            +
                      raise ArgumentError if post.blank?
         | 
| 66 | 
            +
                      super
         | 
| 67 | 
            +
                      @params.merge!(Hash.from_xml(Base64.decode64(xml))["response"])
         | 
| 68 | 
            +
                    end
         | 
| 69 | 
            +
             | 
| 70 | 
            +
                    def xml
         | 
| 71 | 
            +
                      @params["operation_xml"]
         | 
| 72 | 
            +
                    end
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                    def complete?
         | 
| 75 | 
            +
                      status == 'success'
         | 
| 76 | 
            +
                    end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                    def account
         | 
| 79 | 
            +
                      params['merchant_id']
         | 
| 80 | 
            +
                    end
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                    def amount
         | 
| 83 | 
            +
                      BigDecimal.new(gross)
         | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                    def item_id
         | 
| 87 | 
            +
                      params['order_id']
         | 
| 88 | 
            +
                    end
         | 
| 89 | 
            +
             | 
| 90 | 
            +
                    def transaction_id
         | 
| 91 | 
            +
                      params['transaction_id']
         | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    def action_name
         | 
| 95 | 
            +
                      params['action_name'] # either 'result_url' or 'server_url'
         | 
| 96 | 
            +
                    end
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                    def version
         | 
| 99 | 
            +
                      params['version']
         | 
| 100 | 
            +
                    end
         | 
| 101 | 
            +
             | 
| 102 | 
            +
                    def sender_phone
         | 
| 103 | 
            +
                      params['sender_phone']
         | 
| 104 | 
            +
                    end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                    def security_key
         | 
| 107 | 
            +
                      params[OffsitePayments::Integrations::Liqpay.signature_parameter_name]
         | 
| 108 | 
            +
                    end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
                    def gross
         | 
| 111 | 
            +
                      params['amount']
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    def currency
         | 
| 115 | 
            +
                      params['currency']
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                    def status
         | 
| 119 | 
            +
                      params['status'] # 'success', 'failure' or 'wait_secure'
         | 
| 120 | 
            +
                    end
         | 
| 121 | 
            +
             | 
| 122 | 
            +
                    def code
         | 
| 123 | 
            +
                      params['code']
         | 
| 124 | 
            +
                    end
         | 
| 125 | 
            +
             | 
| 126 | 
            +
                    def generate_signature_string
         | 
| 127 | 
            +
                      "#{@options[:secret]}#{Base64.decode64(xml)}#{@options[:secret]}"
         | 
| 128 | 
            +
                    end
         | 
| 129 | 
            +
             | 
| 130 | 
            +
                    def generate_signature
         | 
| 131 | 
            +
                      Base64.encode64(Digest::SHA1.digest(generate_signature_string)).strip
         | 
| 132 | 
            +
                    end
         | 
| 133 | 
            +
             | 
| 134 | 
            +
                    def acknowledge(authcode = nil)
         | 
| 135 | 
            +
                      security_key == generate_signature
         | 
| 136 | 
            +
                    end
         | 
| 137 | 
            +
                  end
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                  class Return < OffsitePayments::Return
         | 
| 140 | 
            +
                    def self.recognizes?(params)
         | 
| 141 | 
            +
                      params.has_key?('amount') && params.has_key?('order_id')
         | 
| 142 | 
            +
                    end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                    def initialize(post)
         | 
| 145 | 
            +
                      super
         | 
| 146 | 
            +
                      xml = Base64.decode64(@params["operation_xml"])
         | 
| 147 | 
            +
                      @params.merge!(Hash.from_xml(xml)["response"])
         | 
| 148 | 
            +
                    end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                    def complete?
         | 
| 151 | 
            +
                      status == 'success'
         | 
| 152 | 
            +
                    end
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                    def account
         | 
| 155 | 
            +
                      params['merchant_id']
         | 
| 156 | 
            +
                    end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                    def amount
         | 
| 159 | 
            +
                      BigDecimal.new(gross)
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                    def item_id
         | 
| 163 | 
            +
                      params['order_id']
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    def transaction_id
         | 
| 167 | 
            +
                      params['transaction_id']
         | 
| 168 | 
            +
                    end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                    def action_name
         | 
| 171 | 
            +
                      params['action_name'] # either 'result_url' or 'server_url'
         | 
| 172 | 
            +
                    end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                    def version
         | 
| 175 | 
            +
                      params['version']
         | 
| 176 | 
            +
                    end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                    def sender_phone
         | 
| 179 | 
            +
                      params['sender_phone']
         | 
| 180 | 
            +
                    end
         | 
| 181 | 
            +
             | 
| 182 | 
            +
                    def security_key
         | 
| 183 | 
            +
                      params[OffsitePayments::Integrations::Liqpay.signature_parameter_name]
         | 
| 184 | 
            +
                    end
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    def gross
         | 
| 187 | 
            +
                      params['amount']
         | 
| 188 | 
            +
                    end
         | 
| 189 | 
            +
             | 
| 190 | 
            +
                    def currency
         | 
| 191 | 
            +
                      params['currency']
         | 
| 192 | 
            +
                    end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                    def status
         | 
| 195 | 
            +
                      params['status'] # 'success', 'failure' or 'wait_secure'
         | 
| 196 | 
            +
                    end
         | 
| 197 | 
            +
             | 
| 198 | 
            +
                    def code
         | 
| 199 | 
            +
                      params['code']
         | 
| 200 | 
            +
                    end
         | 
| 201 | 
            +
             | 
| 202 | 
            +
                    def generate_signature_string
         | 
| 203 | 
            +
                      ['', version, @options[:secret], action_name, sender_phone, account, gross, currency, item_id, transaction_id, status, code, ''].flatten.compact.join('|')
         | 
| 204 | 
            +
                    end
         | 
| 205 | 
            +
             | 
| 206 | 
            +
                    def generate_signature
         | 
| 207 | 
            +
                      Base64.encode64(Digest::SHA1.digest(generate_signature_string)).gsub(/\n/, '')
         | 
| 208 | 
            +
                    end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                    def acknowledge(authcode = nil)
         | 
| 211 | 
            +
                      security_key == generate_signature
         | 
| 212 | 
            +
                    end
         | 
| 213 | 
            +
                  end
         | 
| 214 | 
            +
                end
         | 
| 215 | 
            +
              end
         | 
| 216 | 
            +
            end
         | 
| @@ -0,0 +1,231 @@ | |
| 1 | 
            +
            module OffsitePayments #:nodoc:
         | 
| 2 | 
            +
              module Integrations #:nodoc:
         | 
| 3 | 
            +
                # USAGE:
         | 
| 4 | 
            +
                #
         | 
| 5 | 
            +
                # First define Maksuturva seller id and authcode in an initializer:
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                #   MAKSUTURVA_SELLERID = "testikauppias"
         | 
| 8 | 
            +
                #   MAKSUTURVA_AUTHCODE = "11223344556677889900"
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # Then in view do something like this (use dynamic values for your app)
         | 
| 11 | 
            +
                #
         | 
| 12 | 
            +
                #   <% payment_service_for 2, MAKSUTURVA_SELLERID,
         | 
| 13 | 
            +
                #           :amount => "200,00", :currency => 'EUR', :credential2 => MAKSUTURVA_AUTHCODE,
         | 
| 14 | 
            +
                #           :service => :maksuturva do |service|
         | 
| 15 | 
            +
                #       service.pmt_reference = "134662"
         | 
| 16 | 
            +
                #       service.pmt_duedate = "24.06.2012"
         | 
| 17 | 
            +
                #       service.customer :phone => "0405051909",
         | 
| 18 | 
            +
                #           :email => "antti@example.com"
         | 
| 19 | 
            +
                #       service.billing_address :city => "Helsinki",
         | 
| 20 | 
            +
                #           :address1 => "Lorem street",
         | 
| 21 | 
            +
                #           :state => "-",
         | 
| 22 | 
            +
                #           :country => 'Finland',
         | 
| 23 | 
            +
                #           :zip => "00530"
         | 
| 24 | 
            +
                #       service.pmt_orderid = "2"
         | 
| 25 | 
            +
                #       service.pmt_buyername = "Antti Akonniemi"
         | 
| 26 | 
            +
                #       service.pmt_deliveryname = "Antti Akonniemi"
         | 
| 27 | 
            +
                #       service.pmt_deliveryaddress = "Köydenpunojankatu 13"
         | 
| 28 | 
            +
                #       service.pmt_deliverypostalcode = "00180"
         | 
| 29 | 
            +
                #       service.pmt_deliverycity = "Helsinki"
         | 
| 30 | 
            +
                #       service.pmt_deliverycountry = "FI"
         | 
| 31 | 
            +
                #       service.pmt_rows = 1
         | 
| 32 | 
            +
                #       service.pmt_row_name1 = "testi"
         | 
| 33 | 
            +
                #       service.pmt_row_desc1 = "Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum."
         | 
| 34 | 
            +
                #       service.pmt_row_articlenr1 = "1"
         | 
| 35 | 
            +
                #       service.pmt_row_quantity1 = "1"
         | 
| 36 | 
            +
                #       service.pmt_row_deliverydate1 = "26.6.2012"
         | 
| 37 | 
            +
                #       service.pmt_row_price_gross1 = "200,00"
         | 
| 38 | 
            +
                #       service.pmt_row_vat1= "23,00"
         | 
| 39 | 
            +
                #       service.pmt_row_discountpercentage1 = "0,00"
         | 
| 40 | 
            +
                #       service.pmt_row_type1 = "1"
         | 
| 41 | 
            +
                #       service.pmt_charset = "UTF-8"
         | 
| 42 | 
            +
                #       service.pmt_charsethttp = "UTF-8"
         | 
| 43 | 
            +
                #
         | 
| 44 | 
            +
                #       service.return_url "http://localhost:3000/process"
         | 
| 45 | 
            +
                #       service.cancel_return_url "http://example.com"
         | 
| 46 | 
            +
                #       service.pmt_errorreturn "http://example.com"
         | 
| 47 | 
            +
                #
         | 
| 48 | 
            +
                #       service.pmt_delayedpayreturn "http://example.com"
         | 
| 49 | 
            +
                #       service.pmt_escrow "N"
         | 
| 50 | 
            +
                #       service.pmt_escrowchangeallowed "N"
         | 
| 51 | 
            +
                #       service.pmt_sellercosts "0,00"
         | 
| 52 | 
            +
                #       service.pmt_keygeneration "001"
         | 
| 53 | 
            +
                #        %>
         | 
| 54 | 
            +
                #
         | 
| 55 | 
            +
                # Then in the controller handle the return with something like this
         | 
| 56 | 
            +
                #
         | 
| 57 | 
            +
                #   def ipn
         | 
| 58 | 
            +
                #     notify = OffsitePayments::Integrations::Maksuturva::Notification.new(params)
         | 
| 59 | 
            +
                #
         | 
| 60 | 
            +
                #     if notify.acknowledge(MAKSUTURVA_AUTHCODE)
         | 
| 61 | 
            +
                #       # Process order
         | 
| 62 | 
            +
                #     else
         | 
| 63 | 
            +
                #       # Show error
         | 
| 64 | 
            +
                #     end
         | 
| 65 | 
            +
                #   end
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # For full list of available parameters etc check the integration documents
         | 
| 68 | 
            +
                # here:
         | 
| 69 | 
            +
                #
         | 
| 70 | 
            +
                #   https://www.maksuturva.fi/services/vendor_services/integration_guidelines.html
         | 
| 71 | 
            +
                module Maksuturva
         | 
| 72 | 
            +
                  mattr_accessor :service_url
         | 
| 73 | 
            +
                  self.service_url = 'https://www.maksuturva.fi/NewPaymentExtended.pmt'
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                  def self.notification(post)
         | 
| 76 | 
            +
                    Notification.new(post)
         | 
| 77 | 
            +
                  end
         | 
| 78 | 
            +
             | 
| 79 | 
            +
                  class Helper < OffsitePayments::Helper
         | 
| 80 | 
            +
                    def initialize(order, account, options = {})
         | 
| 81 | 
            +
                      md5secret options.delete(:credential2)
         | 
| 82 | 
            +
                      super
         | 
| 83 | 
            +
                      add_field("pmt_action", "NEW_PAYMENT_EXTENDED")
         | 
| 84 | 
            +
                      add_field("pmt_version", "0004")
         | 
| 85 | 
            +
                      add_field("pmt_sellerid", account)
         | 
| 86 | 
            +
                      add_field("pmt_hashversion", "MD5")
         | 
| 87 | 
            +
                    end
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                    def md5secret(value)
         | 
| 90 | 
            +
                      @md5secret = value
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
             | 
| 93 | 
            +
                    def form_fields
         | 
| 94 | 
            +
                      @fields.merge("pmt_hash" => generate_md5string)
         | 
| 95 | 
            +
                    end
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                    def generate_md5string
         | 
| 98 | 
            +
                      fields = [@fields["pmt_action"], @fields["pmt_version"]]
         | 
| 99 | 
            +
                      fields += [@fields["pmt_selleriban"]] unless @fields["pmt_selleriban"].nil?
         | 
| 100 | 
            +
                      fields += [@fields["pmt_id"], @fields["pmt_orderid"], @fields["pmt_reference"], @fields["pmt_duedate"],
         | 
| 101 | 
            +
                      @fields["pmt_amount"], @fields["pmt_currency"], @fields["pmt_okreturn"], @fields["pmt_errorreturn"], @fields["pmt_cancelreturn"],
         | 
| 102 | 
            +
                      @fields["pmt_delayedpayreturn"], @fields["pmt_escrow"], @fields["pmt_escrowchangeallowed"]]
         | 
| 103 | 
            +
             | 
| 104 | 
            +
                      fields += [@fields["pmt_invoicefromseller"]] unless @fields["pmt_invoicefromseller"].nil?
         | 
| 105 | 
            +
                      fields += [@fields["pmt_paymentmethod"]] unless @fields["pmt_paymentmethod"].nil?
         | 
| 106 | 
            +
                      fields += [@fields["pmt_buyeridentificationcode"]] unless @fields["pmt_buyeridentificationcode"].nil?
         | 
| 107 | 
            +
             | 
| 108 | 
            +
             | 
| 109 | 
            +
                      fields += [@fields["pmt_buyername"], @fields["pmt_buyeraddress"], @fields["pmt_buyerpostalcode"], @fields["pmt_buyercity"],
         | 
| 110 | 
            +
                      @fields["pmt_buyercountry"], @fields["pmt_deliveryname"], @fields["pmt_deliveryaddress"], @fields["pmt_deliverypostalcode"], @fields["pmt_deliverycity"],
         | 
| 111 | 
            +
                      @fields["pmt_deliverycountry"], @fields["pmt_sellercosts"]]
         | 
| 112 | 
            +
             | 
| 113 | 
            +
                      (1..@fields["pmt_rows"].to_i).each do |i|
         | 
| 114 | 
            +
                        fields += [@fields["pmt_row_name#{i}"], @fields["pmt_row_desc#{i}"], @fields["pmt_row_quantity#{i}"]]
         | 
| 115 | 
            +
                        fields += [@fields["pmt_row_articlenr#{i}"]] unless @fields["pmt_row_articlenr#{i}"].nil?
         | 
| 116 | 
            +
                        fields += [@fields["pmt_row_unit#{i}"]] unless @fields["pmt_row_unit#{i}"].nil?
         | 
| 117 | 
            +
                        fields += [@fields["pmt_row_deliverydate#{i}"]]
         | 
| 118 | 
            +
                        fields += [@fields["pmt_row_price_gross#{i}"]] unless @fields["pmt_row_price_gross#{i}"].nil?
         | 
| 119 | 
            +
                        fields += [@fields["pmt_row_price_net#{i}"]] unless @fields["pmt_row_price_net#{i}"].nil?
         | 
| 120 | 
            +
                        fields += [@fields["pmt_row_vat#{i}"], @fields["pmt_row_discountpercentage#{i}"], @fields["pmt_row_type#{i}"]]
         | 
| 121 | 
            +
                      end
         | 
| 122 | 
            +
                      fields += [@md5secret]
         | 
| 123 | 
            +
                      fields = fields.join("&") + "&"
         | 
| 124 | 
            +
                      Digest::MD5.hexdigest(fields).upcase
         | 
| 125 | 
            +
                    end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                    mapping :pmt_selleriban, "pmt_selleriban"
         | 
| 128 | 
            +
                    mapping :pmt_reference, "pmt_reference"
         | 
| 129 | 
            +
                    mapping :pmt_duedate, "pmt_duedate"
         | 
| 130 | 
            +
                    mapping :pmt_userlocale, "pmt_userlocale"
         | 
| 131 | 
            +
                    mapping :pmt_escrow, "pmt_escrow"
         | 
| 132 | 
            +
                    mapping :pmt_escrowchangeallowed, "pmt_escrowchangeallowed"
         | 
| 133 | 
            +
                    mapping :pmt_invoicefromseller, "pmt_invoicefromseller"
         | 
| 134 | 
            +
                    mapping :pmt_paymentmethod, "pmt_paymentmethod"
         | 
| 135 | 
            +
                    mapping :pmt_buyeridentificationcode, "pmt_buyeridentificationcode"
         | 
| 136 | 
            +
                    mapping :pmt_buyername, "pmt_buyername"
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                    mapping :account, ''
         | 
| 139 | 
            +
                    mapping :currency, 'pmt_currency'
         | 
| 140 | 
            +
                    mapping :amount, 'pmt_amount'
         | 
| 141 | 
            +
             | 
| 142 | 
            +
                    mapping :order, 'pmt_id'
         | 
| 143 | 
            +
                    mapping :pmt_orderid, 'pmt_orderid'
         | 
| 144 | 
            +
                    mapping :pmt_deliveryname, "pmt_deliveryname"
         | 
| 145 | 
            +
                    mapping :pmt_deliveryaddress, "pmt_deliveryaddress"
         | 
| 146 | 
            +
                    mapping :pmt_deliverypostalcode, "pmt_deliverypostalcode"
         | 
| 147 | 
            +
                    mapping :pmt_deliverycity, "pmt_deliverycity"
         | 
| 148 | 
            +
                    mapping :pmt_deliverycountry, "pmt_deliverycountry"
         | 
| 149 | 
            +
                    mapping :pmt_sellercosts, "pmt_sellercosts"
         | 
| 150 | 
            +
                    mapping :pmt_rows, "pmt_rows"
         | 
| 151 | 
            +
             | 
| 152 | 
            +
                    (1..499.to_i).each do |i|
         | 
| 153 | 
            +
                      mapping "pmt_row_name#{i}".to_sym, "pmt_row_name#{i}"
         | 
| 154 | 
            +
                      mapping "pmt_row_desc#{i}".to_sym, "pmt_row_desc#{i}"
         | 
| 155 | 
            +
                      mapping "pmt_row_quantity#{i}".to_sym, "pmt_row_quantity#{i}"
         | 
| 156 | 
            +
                      mapping "pmt_row_articlenr#{i}".to_sym, "pmt_row_articlenr#{i}"
         | 
| 157 | 
            +
                      mapping "pmt_row_unit#{i}".to_sym, "pmt_row_unit#{i}"
         | 
| 158 | 
            +
                      mapping "pmt_row_deliverydate#{i}".to_sym, "pmt_row_deliverydate#{i}"
         | 
| 159 | 
            +
                      mapping "pmt_row_price_gross#{i}".to_sym, "pmt_row_price_gross#{i}"
         | 
| 160 | 
            +
                      mapping "pmt_row_price_net#{i}".to_sym, "pmt_row_price_net#{i}"
         | 
| 161 | 
            +
                      mapping "pmt_row_vat#{i}".to_sym, "pmt_row_vat#{i}"
         | 
| 162 | 
            +
                      mapping "pmt_row_discountpercentage#{i}".to_sym, "pmt_row_discountpercentage#{i}"
         | 
| 163 | 
            +
                      mapping "pmt_row_type#{i}".to_sym, "pmt_row_type#{i}"
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    mapping :pmt_charset, "pmt_charset"
         | 
| 167 | 
            +
                    mapping :pmt_charsethttp, "pmt_charsethttp"
         | 
| 168 | 
            +
                    mapping :pmt_hashversion, "pmt_hashversion"
         | 
| 169 | 
            +
                    mapping :pmt_keygeneration, "pmt_keygeneration"
         | 
| 170 | 
            +
                    mapping :customer, :email      => 'pmt_buyeremail',
         | 
| 171 | 
            +
                                       :phone      => 'pmt_buyerphone'
         | 
| 172 | 
            +
             | 
| 173 | 
            +
                    mapping :billing_address, :city     => 'pmt_buyercity',
         | 
| 174 | 
            +
                                              :address1 => "pmt_buyeraddress",
         | 
| 175 | 
            +
                                              :address2 => '',
         | 
| 176 | 
            +
                                              :state    => '',
         | 
| 177 | 
            +
                                              :zip      => "pmt_buyerpostalcode",
         | 
| 178 | 
            +
                                              :country  => 'pmt_buyercountry'
         | 
| 179 | 
            +
             | 
| 180 | 
            +
                    mapping :notify_url, ''
         | 
| 181 | 
            +
                    mapping :return_url, 'pmt_okreturn'
         | 
| 182 | 
            +
                    mapping :pmt_errorreturn, 'pmt_errorreturn'
         | 
| 183 | 
            +
                    mapping :pmt_delayedpayreturn, 'pmt_delayedpayreturn'
         | 
| 184 | 
            +
                    mapping :cancel_return_url, 'pmt_cancelreturn'
         | 
| 185 | 
            +
             | 
| 186 | 
            +
                    mapping :description, ''
         | 
| 187 | 
            +
                    mapping :tax, ''
         | 
| 188 | 
            +
                    mapping :shipping, ''
         | 
| 189 | 
            +
                  end
         | 
| 190 | 
            +
             | 
| 191 | 
            +
                  class Notification < OffsitePayments::Notification
         | 
| 192 | 
            +
                    def complete?
         | 
| 193 | 
            +
                      true
         | 
| 194 | 
            +
                    end
         | 
| 195 | 
            +
             | 
| 196 | 
            +
                    def transaction_id
         | 
| 197 | 
            +
                      params["pmt_id"]
         | 
| 198 | 
            +
                    end
         | 
| 199 | 
            +
             | 
| 200 | 
            +
                    def security_key
         | 
| 201 | 
            +
                      params["pmt_hash"]
         | 
| 202 | 
            +
                    end
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    def gross
         | 
| 205 | 
            +
                      params["pmt_amount"]
         | 
| 206 | 
            +
                    end
         | 
| 207 | 
            +
             | 
| 208 | 
            +
                    def currency
         | 
| 209 | 
            +
                      params["pmt_currency"]
         | 
| 210 | 
            +
                    end
         | 
| 211 | 
            +
             | 
| 212 | 
            +
                    def status
         | 
| 213 | 
            +
                      "PAID"
         | 
| 214 | 
            +
                    end
         | 
| 215 | 
            +
             | 
| 216 | 
            +
                    def acknowledge(authcode = nil)
         | 
| 217 | 
            +
                      return_authcode = [params["pmt_action"], params["pmt_version"], params["pmt_id"], params["pmt_reference"], params["pmt_amount"], params["pmt_currency"], params["pmt_sellercosts"], params["pmt_paymentmethod"], params["pmt_escrow"], authcode].join("&")
         | 
| 218 | 
            +
                      (Digest::MD5.hexdigest(return_authcode + "&").upcase == params["pmt_hash"])
         | 
| 219 | 
            +
                    end
         | 
| 220 | 
            +
             | 
| 221 | 
            +
                    private
         | 
| 222 | 
            +
             | 
| 223 | 
            +
                    def parse(post)
         | 
| 224 | 
            +
                      post.each do |key, value|
         | 
| 225 | 
            +
                        params[key] = value
         | 
| 226 | 
            +
                      end
         | 
| 227 | 
            +
                    end
         | 
| 228 | 
            +
                  end
         | 
| 229 | 
            +
                end
         | 
| 230 | 
            +
              end
         | 
| 231 | 
            +
            end
         | 
| @@ -0,0 +1,213 @@ | |
| 1 | 
            +
            module OffsitePayments #:nodoc:
         | 
| 2 | 
            +
              module Integrations #:nodoc:
         | 
| 3 | 
            +
                module MollieIdeal
         | 
| 4 | 
            +
                  class API
         | 
| 5 | 
            +
                    include ActiveMerchant::PostsData
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                    attr_reader :token
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                    def initialize(token)
         | 
| 10 | 
            +
                      @token = token
         | 
| 11 | 
            +
                    end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                    def get_request(resource, params = nil)
         | 
| 14 | 
            +
                      uri = URI.parse(MOLLIE_API_V1_URI + resource)
         | 
| 15 | 
            +
                      uri.query = params.map { |k,v| "#{CGI.escape(k)}=#{CGI.escape(v)}}"}.join('&') if params
         | 
| 16 | 
            +
                      headers = { "Authorization" => "Bearer #{token}", "Content-Type" => "application/json" }
         | 
| 17 | 
            +
                      JSON.parse(ssl_get(uri.to_s, headers))
         | 
| 18 | 
            +
                    end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                    def post_request(resource, params = nil)
         | 
| 21 | 
            +
                      uri = URI.parse(MOLLIE_API_V1_URI + resource)
         | 
| 22 | 
            +
                      headers = { "Authorization" => "Bearer #{token}", "Content-Type" => "application/json" }
         | 
| 23 | 
            +
                      data = params.nil? ? nil : JSON.dump(params)
         | 
| 24 | 
            +
                      JSON.parse(ssl_post(uri.to_s, data, headers))
         | 
| 25 | 
            +
                    end
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  RedirectError = Class.new(ActiveMerchant::ActiveMerchantError)
         | 
| 29 | 
            +
             | 
| 30 | 
            +
                  MOLLIE_API_V1_URI = 'https://api.mollie.nl/v1/'.freeze
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  mattr_accessor :live_issuers
         | 
| 33 | 
            +
                  self.live_issuers = [
         | 
| 34 | 
            +
                    ["ABN AMRO", "ideal_ABNANL2A"],
         | 
| 35 | 
            +
                    ["ASN Bank", "ideal_ASNBNL21"],
         | 
| 36 | 
            +
                    ["Friesland Bank", "ideal_FRBKNL2L"],
         | 
| 37 | 
            +
                    ["ING", "ideal_INGBNL2A"],
         | 
| 38 | 
            +
                    ["Knab", "ideal_KNABNL2H"],
         | 
| 39 | 
            +
                    ["Rabobank", "ideal_RABONL2U"],
         | 
| 40 | 
            +
                    ["RegioBank", "ideal_RBRBNL21"],
         | 
| 41 | 
            +
                    ["SNS Bank", "ideal_SNSBNL2A"],
         | 
| 42 | 
            +
                    ["Triodos Bank", "ideal_TRIONL2U"],
         | 
| 43 | 
            +
                    ["van Lanschot", "ideal_FVLBNL22"]
         | 
| 44 | 
            +
                  ]
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  mattr_accessor :test_issuers
         | 
| 47 | 
            +
                  self.test_issuers = [
         | 
| 48 | 
            +
                    ["TBM Bank", "ideal_TESTNL99"]
         | 
| 49 | 
            +
                  ]
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def self.notification(post, options = {})
         | 
| 52 | 
            +
                    Notification.new(post, options)
         | 
| 53 | 
            +
                  end
         | 
| 54 | 
            +
             | 
| 55 | 
            +
                  def self.return(post, options = {})
         | 
| 56 | 
            +
                    Return.new(post, options)
         | 
| 57 | 
            +
                  end
         | 
| 58 | 
            +
             | 
| 59 | 
            +
                  def self.live?
         | 
| 60 | 
            +
                    OffsitePayments.mode == :production
         | 
| 61 | 
            +
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  def self.requires_redirect_param?
         | 
| 64 | 
            +
                    true
         | 
| 65 | 
            +
                  end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                  def self.redirect_param_label
         | 
| 68 | 
            +
                    "Select your bank"
         | 
| 69 | 
            +
                  end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                  def self.redirect_param_options(options = {})
         | 
| 72 | 
            +
                    return test_issuers if options[:credential1].blank?
         | 
| 73 | 
            +
                    options[:credential1].start_with?('live_') ? live_issuers : test_issuers
         | 
| 74 | 
            +
                  end
         | 
| 75 | 
            +
             | 
| 76 | 
            +
                  def self.retrieve_issuers(token)
         | 
| 77 | 
            +
                    response = API.new(token).get_request("issuers")
         | 
| 78 | 
            +
                    response['data']
         | 
| 79 | 
            +
                      .select { |issuer| issuer['method'] == 'ideal' }
         | 
| 80 | 
            +
                      .map { |issuer| [issuer['name'], issuer['id']] }
         | 
| 81 | 
            +
                  end
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                  def self.create_payment(token, params)
         | 
| 84 | 
            +
                    API.new(token).post_request('payments', params)
         | 
| 85 | 
            +
                  end
         | 
| 86 | 
            +
             | 
| 87 | 
            +
                  def self.check_payment_status(token, payment_id)
         | 
| 88 | 
            +
                    API.new(token).get_request("payments/#{payment_id}")
         | 
| 89 | 
            +
                  end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  class Helper < OffsitePayments::Helper
         | 
| 92 | 
            +
                    attr_reader :transaction_id, :redirect_paramaters, :token
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                    def initialize(order, account, options = {})
         | 
| 95 | 
            +
                      @token = account
         | 
| 96 | 
            +
                      @redirect_paramaters = {
         | 
| 97 | 
            +
                        :amount => options[:amount],
         | 
| 98 | 
            +
                        :description => options[:description],
         | 
| 99 | 
            +
                        :issuer => options[:redirect_param],
         | 
| 100 | 
            +
                        :redirectUrl => options[:return_url],
         | 
| 101 | 
            +
                        :method => 'ideal',
         | 
| 102 | 
            +
                        :metadata => { :order => order }
         | 
| 103 | 
            +
                      }
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                      @redirect_paramaters[:webhookUrl] = options[:notify_url] if options[:notify_url]
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                      super
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                      raise ArgumentError, "The redirect_param option needs to be set to the bank_id the customer selected." if options[:redirect_param].blank?
         | 
| 110 | 
            +
                      raise ArgumentError, "The return_url option needs to be set." if options[:return_url].blank?
         | 
| 111 | 
            +
                      raise ArgumentError, "The description option needs to be set." if options[:description].blank?
         | 
| 112 | 
            +
                    end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                    def credential_based_url
         | 
| 115 | 
            +
                      response = request_redirect
         | 
| 116 | 
            +
                      @transaction_id = response['id']
         | 
| 117 | 
            +
             | 
| 118 | 
            +
                      uri = URI.parse(response['links']['paymentUrl'])
         | 
| 119 | 
            +
                      set_form_fields_for_redirect(uri)
         | 
| 120 | 
            +
                      uri.query = ''
         | 
| 121 | 
            +
                      uri.to_s.sub(/\?\z/, '')
         | 
| 122 | 
            +
                    end
         | 
| 123 | 
            +
             | 
| 124 | 
            +
                    def form_method
         | 
| 125 | 
            +
                      "GET"
         | 
| 126 | 
            +
                    end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                    def set_form_fields_for_redirect(uri)
         | 
| 129 | 
            +
                      CGI.parse(uri.query).each do |key, value|
         | 
| 130 | 
            +
                        if value.is_a?(Array) && value.length == 1
         | 
| 131 | 
            +
                          add_field(key, value.first)
         | 
| 132 | 
            +
                        else
         | 
| 133 | 
            +
                          add_field(key, value)
         | 
| 134 | 
            +
                        end
         | 
| 135 | 
            +
                      end
         | 
| 136 | 
            +
                    end
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                    def request_redirect
         | 
| 139 | 
            +
                      MollieIdeal.create_payment(token, redirect_paramaters)
         | 
| 140 | 
            +
                    rescue ActiveMerchant::ResponseError => e
         | 
| 141 | 
            +
                      if %w(401 403 422).include?(e.response.code)
         | 
| 142 | 
            +
                        error = JSON.parse(e.response.body)['error']['message']
         | 
| 143 | 
            +
                        raise ActionViewHelperError, error
         | 
| 144 | 
            +
                      else
         | 
| 145 | 
            +
                        raise
         | 
| 146 | 
            +
                      end
         | 
| 147 | 
            +
                    end
         | 
| 148 | 
            +
                  end
         | 
| 149 | 
            +
             | 
| 150 | 
            +
                  class Notification < OffsitePayments::Notification
         | 
| 151 | 
            +
                    def initialize(post_arguments, options = {})
         | 
| 152 | 
            +
                      super
         | 
| 153 | 
            +
             | 
| 154 | 
            +
                      raise ArgumentError, "The transaction_id needs to be included in the query string." if transaction_id.nil?
         | 
| 155 | 
            +
                      raise ArgumentError, "The credential1 option needs to be set to the Mollie API key." if api_key.blank?
         | 
| 156 | 
            +
                    end
         | 
| 157 | 
            +
             | 
| 158 | 
            +
                    def complete?
         | 
| 159 | 
            +
                      true
         | 
| 160 | 
            +
                    end
         | 
| 161 | 
            +
             | 
| 162 | 
            +
                    def item_id
         | 
| 163 | 
            +
                      params['metadata']['order']
         | 
| 164 | 
            +
                    end
         | 
| 165 | 
            +
             | 
| 166 | 
            +
                    def transaction_id
         | 
| 167 | 
            +
                      params['id']
         | 
| 168 | 
            +
                    end
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                    def api_key
         | 
| 171 | 
            +
                      @options[:credential1]
         | 
| 172 | 
            +
                    end
         | 
| 173 | 
            +
             | 
| 174 | 
            +
                    def currency
         | 
| 175 | 
            +
                      "EUR"
         | 
| 176 | 
            +
                    end
         | 
| 177 | 
            +
             | 
| 178 | 
            +
                    # the money amount we received in X.2 decimal.
         | 
| 179 | 
            +
                    def gross
         | 
| 180 | 
            +
                      @params['amount']
         | 
| 181 | 
            +
                    end
         | 
| 182 | 
            +
             | 
| 183 | 
            +
                    def gross_cents
         | 
| 184 | 
            +
                      (BigDecimal.new(@params['amount'], 2) * 100).to_i
         | 
| 185 | 
            +
                    end
         | 
| 186 | 
            +
             | 
| 187 | 
            +
                    def status
         | 
| 188 | 
            +
                      case @params['status']
         | 
| 189 | 
            +
                        when 'open';                 'Pending'
         | 
| 190 | 
            +
                        when 'paidout', 'paid';      'Completed'
         | 
| 191 | 
            +
                        else                         'Failed'
         | 
| 192 | 
            +
                      end
         | 
| 193 | 
            +
                    end
         | 
| 194 | 
            +
             | 
| 195 | 
            +
                    def test?
         | 
| 196 | 
            +
                      @params['mode'] == 'test'
         | 
| 197 | 
            +
                    end
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                    def acknowledge(authcode = nil)
         | 
| 200 | 
            +
                      @params = check_payment_status(transaction_id)
         | 
| 201 | 
            +
                      true
         | 
| 202 | 
            +
                    end
         | 
| 203 | 
            +
             | 
| 204 | 
            +
                    def check_payment_status(transaction_id)
         | 
| 205 | 
            +
                      MollieIdeal.check_payment_status(@options[:credential1], transaction_id)
         | 
| 206 | 
            +
                    end
         | 
| 207 | 
            +
                  end
         | 
| 208 | 
            +
             | 
| 209 | 
            +
                  class Return < OffsitePayments::Return
         | 
| 210 | 
            +
                  end
         | 
| 211 | 
            +
                end
         | 
| 212 | 
            +
              end
         | 
| 213 | 
            +
            end
         |