diff --git a/app/models/bank_link.rb b/app/models/bank_link.rb deleted file mode 100644 index 979e57ece..000000000 --- a/app/models/bank_link.rb +++ /dev/null @@ -1,158 +0,0 @@ -class BankLink - module Base - def prepend_size(value) - value = (value || "").to_s.strip - string = "" - string << sprintf("%03i", value.size) - string << value - end - end - - class Request - include Base - include ActionView::Helpers::NumberHelper - - # need controller here in order to handle random ports and domains - # I don't want to do it but has to - attr_accessor :type, :invoice, :controller - def initialize(type, invoice, controller) - @type, @invoice, @controller = type, invoice, controller - end - - def url - ENV["payments_#{type}_url"] - end - - def fields - @fields ||= (hash = {} - hash["VK_SERVICE"] = "1012" - hash["VK_VERSION"] = "008" - hash["VK_SND_ID"] = ENV["payments_#{type}_seller_account"] - hash["VK_STAMP"] = invoice.number - hash["VK_AMOUNT"] = number_with_precision(invoice.total, :precision => 2, :separator => ".") - hash["VK_CURR"] = invoice.currency - hash["VK_REF"] = "" - hash["VK_MSG"] = invoice.order - hash["VK_RETURN"] = controller.registrar_return_payment_with_url(type) - hash["VK_CANCEL"] = controller.registrar_return_payment_with_url(type) - hash["VK_DATETIME"] = Time.now.strftime("%Y-%m-%dT%H:%M:%S%z") - hash["VK_MAC"] = calc_mac(hash) - hash["VK_ENCODING"] = "UTF-8" - hash["VK_LANG"] = "ENG" - hash) - end - - def calc_mac(fields) - pars = %w(VK_SERVICE VK_VERSION VK_SND_ID VK_STAMP VK_AMOUNT VK_CURR VK_REF - VK_MSG VK_RETURN VK_CANCEL VK_DATETIME).freeze - data = pars.map{|e| prepend_size(fields[e]) }.join - - sign(data) - end - - def make_transaction - transaction = BankTransaction.where(description: fields["VK_MSG"]).first_or_initialize( - reference_no: invoice.reference_no, - currency: invoice.currency, - iban: invoice.seller_iban - ) - - transaction.save! - end - - private - def sign(data) - private_key = OpenSSL::PKey::RSA.new(File.read(ENV["payments_#{type}_seller_private"])) - - signed_data = private_key.sign(OpenSSL::Digest::SHA1.new, data) - signed_data = Base64.encode64(signed_data).gsub(/\n|\r/, '') - signed_data - end - end - - - - - class Response - include Base - include ActionView::Helpers::NumberHelper - - attr_accessor :type, :params, :invoice - def initialize(type, params) - @type, @params = type, params - - @invoice = Invoice.find_by(number: params["VK_STAMP"]) if params["VK_STAMP"].present? - end - - def valid? - !!validate - end - - def ok? - params["VK_SERVICE"] == "1111" - end - - def complete_payment - if valid? - transaction = BankTransaction.find_by(description: params["VK_MSG"]) - transaction.sum = BigDecimal.new(params["VK_AMOUNT"].to_s) - transaction.bank_reference = params['VK_T_NO'] - transaction.buyer_bank_code = params["VK_SND_ID"] - transaction.buyer_iban = params["VK_SND_ACC"] - transaction.buyer_name = params["VK_SND_NAME"] - transaction.paid_at = Time.parse(params["VK_T_DATETIME"]) - transaction.save! - - transaction.autobind_invoice - end - end - - - - def validate - case params["VK_SERVICE"] - when "1111" - validate_success && validate_amount && validate_currency - when "1911" - validate_cancel - else - false - end - end - - def validate_success - pars = %w(VK_SERVICE VK_VERSION VK_SND_ID VK_REC_ID VK_STAMP VK_T_NO VK_AMOUNT VK_CURR - VK_REC_ACC VK_REC_NAME VK_SND_ACC VK_SND_NAME VK_REF VK_MSG VK_T_DATETIME).freeze - - @validate_success ||= ( - data = pars.map{|e| prepend_size(params[e]) }.join - verify_mac(data, params["VK_MAC"]) - ) - end - - def validate_cancel - pars = %w(VK_SERVICE VK_VERSION VK_SND_ID VK_REC_ID VK_STAMP VK_REF VK_MSG).freeze - @validate_cancel ||= ( - data = pars.map{|e| prepend_size(params[e]) }.join - verify_mac(data, params["VK_MAC"]) - ) - end - - def validate_amount - source = number_with_precision(BigDecimal.new(params["VK_AMOUNT"].to_s), precision: 2, separator: ".") - target = number_with_precision(invoice.total, precision: 2, separator: ".") - - source == target - end - - def validate_currency - invoice.currency == params["VK_CURR"] - end - - - def verify_mac(data, mac) - bank_public_key = OpenSSL::X509::Certificate.new(File.read(ENV["payments_#{type}_bank_certificate"])).public_key - bank_public_key.verify(OpenSSL::Digest::SHA1.new, Base64.decode64(mac), data) - end - end -end diff --git a/app/models/payments.rb b/app/models/payments.rb index a04e2e4b9..5d0e8f0a8 100644 --- a/app/models/payments.rb +++ b/app/models/payments.rb @@ -1,6 +1,7 @@ module Payments - PAYMENT_METHODS = ENV['payment_methods'].strip.split(', ').freeze - PAYMENT_BANKLINK_BANKS = ENV['payment_banklink_banks'].strip.split(', ').freeze + PAYMENT_INTERMEDIARIES = ENV['payments_intermediaries'].strip.split(', ').freeze + PAYMENT_BANKLINK_BANKS = ENV['payments_banks'].strip.split(', ').freeze + PAYMENT_METHODS = [PAYMENT_INTERMEDIARIES, PAYMENT_BANKLINK_BANKS].flatten.freeze def self.create_with_type(type, invoice, opts = {}) fail ArgumentError unless PAYMENT_METHODS.include?(type) diff --git a/app/models/payments/bank_link.rb b/app/models/payments/bank_link.rb index 2e119ec67..1ae0436cd 100644 --- a/app/models/payments/bank_link.rb +++ b/app/models/payments/bank_link.rb @@ -94,15 +94,15 @@ module Payments end def seller_account - ENV["#{type}_seller_account"] + ENV["payments_#{type}_seller_account"] end def seller_certificate - ENV["#{type}_seller_certificate"] + ENV["payments_#{type}_seller_private"] end def bank_certificate - ENV["#{type}_bank_certificate"] + ENV["payments_#{type}_bank_certificate"] end end end diff --git a/app/models/payments/base.rb b/app/models/payments/base.rb index aee0dde11..668c7d63d 100644 --- a/app/models/payments/base.rb +++ b/app/models/payments/base.rb @@ -39,7 +39,7 @@ module Payments end def form_url - ENV["#{type}_payment_url"] + ENV["payments_#{type}_url"] end def valid_response? diff --git a/app/models/payments/every_pay.rb b/app/models/payments/every_pay.rb index 3c272f455..e3b2a03f5 100644 --- a/app/models/payments/every_pay.rb +++ b/app/models/payments/every_pay.rb @@ -2,9 +2,9 @@ module Payments class EveryPay < Base # TODO: Move to setting or environment - USER = ENV['every_pay_api_user'].freeze - KEY = ENV['every_pay_api_key'].freeze - ACCOUNT_ID = ENV['every_pay_seller_account'].freeze + USER = ENV['payments_every_pay_api_user'].freeze + KEY = ENV['payments_every_pay_api_key'].freeze + ACCOUNT_ID = ENV['payments_every_pay_seller_account'].freeze SUCCESSFUL_PAYMENT = %w(settled authorized).freeze def form_fields diff --git a/app/views/registrar/payments/every_pay/complete.haml b/app/views/registrar/payments/every_pay/complete.haml deleted file mode 100644 index a9e392b93..000000000 --- a/app/views/registrar/payments/every_pay/complete.haml +++ /dev/null @@ -1,19 +0,0 @@ -.row - .col-md-12 - %h4= "Credit card payment successful" - %hr - %dl.dl-horizontal - %dt= t(:invoice) - %dd= @invoice.reference_no - - %dt= "Card Type" - %dd= params['cc_type'].humanize - - %dt= "Card Holder" - %dd= params['cc_holder_name'] - - %dt= "Card Last four digits" - %dd= params['cc_last_four_digits'] - - %dt= "Valid thru" - %dd= "#{params['cc_month']}/#{params['cc_year']}" diff --git a/app/views/registrar/payments/every_pay/new.haml b/app/views/registrar/payments/every_pay/new.haml deleted file mode 100644 index cdafd15ea..000000000 --- a/app/views/registrar/payments/every_pay/new.haml +++ /dev/null @@ -1,4 +0,0 @@ -= form_tag "https://igw-demo.every-pay.com/transactions/", method: :post do - - @every_pay.keys.each do |k, v| - = hidden_field_tag(k, @every_pay[k]) - = submit_tag t("registrar.invoices.to_card_payment") diff --git a/config/application-example.yml b/config/application-example.yml index e61293b4c..1214ea5d2 100644 --- a/config/application-example.yml +++ b/config/application-example.yml @@ -106,10 +106,13 @@ sk_digi_doc_service_name: 'Testimine' secret_key_base: 'please-change-it-you-can-generate-it-with-rake-secret' devise_secret: 'please-change-it-you-can-generate-it-with-rake-secret' +# You should list only payment methods that +# conform with the Estonian BankLink standard payments_banks: > seb, swed, lhv + payments_seb_url: 'https://www.seb.ee/cgi-bin/dv.sh/ipank.r' payments_seb_bank_certificate: 'eyp_pub.pem' payments_seb_seller_private: 'kaupmees_priv.pem' @@ -123,6 +126,26 @@ payments_lhv_bank_certificate: 'eyp_pub.pem' payments_lhv_seller_private: 'kaupmees_priv.pem' payments_lhv_seller_account: 'testvpos' +# You should list other payment intermediaries here. Each one of them needs their own class in /app/models/payments/ +payments_intermediaries: > + every_pay + +# Other intermediaries should follow this naming convention: +# payments_intermediary_url - URL to intiate payments +# payments_intermediary_seller_account - your username in the bank system +# payments_intermediary_api_user - API username, in case it's different than the seller account +# payments_intermediary_api_key - API key given to you by intermediary +payments_every_pay_url: 'https://igw-demo.every-pay.com/transactions/' +payments_every_pay_seller_account: 'account' +payments_every_pay_api_user: 'api_user' +payments_every_pay_api_key: 'api_key' + user_session_timeout: '3600' # 1 hour secure_session_cookies: 'false' # true|false same_site_session_cookies: 'false' # false|strict|lax + + +# Since the keys for staging are absent from the repo, we need to supply them separate for testing. +test: + payments_seb_bank_certificate: 'test/fixtures/files/seb_bank_cert.pem' + payments_seb_seller_private: 'test/fixtures/files/seb_seller_key.pem' diff --git a/test/integration/registrar/invoices/list_test.rb b/test/integration/registrar/invoices/list_test.rb index 14b19c3e3..b5a61af5b 100644 --- a/test/integration/registrar/invoices/list_test.rb +++ b/test/integration/registrar/invoices/list_test.rb @@ -12,28 +12,15 @@ class ListInvoicesTest < ActionDispatch::IntegrationTest assert_text "Your current account balance is 100,00 EUR" end - - def test_show_single_invoice - @invoice = invoices(:valid) - @registrar_invoices = [] - @registrar_invoices << @invoice - - visit registrar_invoices_path - assert_text "Unpaid", count: 1 - assert_text "Invoice no.", count: 1 - end - - # This bastard fails, only unpaid invoice is attached to the registrar - # TODO: Fix and uncomment def test_show_multiple_invoices - @invoices = invoices(:valid, :cancelled) + @invoices = invoices @registrar_invoices = [] @invoices.each do |invoice| @registrar_invoices << invoice end visit registrar_invoices_path - assert_text "Unpaid", count: 2 - assert_text "Invoice no.", count: 2 + assert_text "Unpaid", count: 5 + assert_text "Invoice no.", count: 7 end end diff --git a/test/integration/registrar/invoices/new_invoice_payment_test.rb b/test/integration/registrar/invoices/new_invoice_payment_test.rb index cee704e3f..ae830107a 100644 --- a/test/integration/registrar/invoices/new_invoice_payment_test.rb +++ b/test/integration/registrar/invoices/new_invoice_payment_test.rb @@ -2,33 +2,10 @@ require 'test_helper' class NewInvoicePaymentTest < ActionDispatch::IntegrationTest setup do - @original_methods = ENV['payment_methods'] - @original_seb_URL = ENV['seb_payment_url'] - @original_bank_certificate = ENV['seb_bank_certificate'] - @original_seller_certificate = ENV['seller_certificate'] - @original_ep_url = ENV['every_pay_payment_url'] - ENV['payment_methods'] = 'seb, swed, every_pay' - ENV['seb_payment_url'] = 'https://example.com/seb_url' - ENV['seb_seller_account'] = 'SEB' - ENV['seb_bank_certificate'] = 'test/fixtures/files/seb_bank_cert.pem' - ENV['seb_seller_certificate'] = 'test/fixtures/files/seb_seller_key.pem' - ENV['every_pay_payment_url'] = 'https://example.com/every_pay_url' @user = users(:api_bestnames) - @original_vat_rate = @user.registrar.vat_rate - @user.registrar.vat_rate = 0.2 - login_as @user end - teardown do - ENV['every_pay_payment_url'] = @original_ep_url - ENV['payment_methods'] = @original_methods - ENV['seb_payment_url'] = @original_seb_URL - ENV['seb_bank_certificate'] = @original_bank_certificate - ENV['seb_seller_certificate'] = @original_seller_certificate - @user.registrar.vat_rate = @original_vat_rate - end - def create_invoice_and_visit_its_page visit registrar_invoices_path click_link_or_button 'Add deposit' @@ -41,20 +18,19 @@ class NewInvoicePaymentTest < ActionDispatch::IntegrationTest create_invoice_and_visit_its_page click_link_or_button 'Seb' form = page.find('form') - assert_equal 'https://example.com/seb_url', form['action'] + assert_equal 'https://www.seb.ee/cgi-bin/dv.sh/ipank.r', form['action'] assert_equal 'post', form['method'] assert_equal '220.00', form.find_by_id('VK_AMOUNT', visible: false).value end def test_create_new_Every_Pay_payment create_invoice_and_visit_its_page - save_and_open_page click_link_or_button 'Every pay' expected_hmac_fields = 'account_id,amount,api_username,callback_url,' + 'customer_url,hmac_fields,nonce,order_reference,timestamp,transaction_type' form = page.find('form') - assert_equal 'https://example.com/every_pay_url', form['action'] + assert_equal 'https://igw-demo.every-pay.com/transactions/', form['action'] assert_equal 'post', form['method'] assert_equal expected_hmac_fields, form.find_by_id('hmac_fields', visible: false).value assert_equal '220.0', form.find_by_id('amount', visible: false).value diff --git a/test/integration/registrar/invoices/new_test.rb b/test/integration/registrar/invoices/new_test.rb index bb398ecde..89a3dd8a3 100644 --- a/test/integration/registrar/invoices/new_test.rb +++ b/test/integration/registrar/invoices/new_test.rb @@ -35,27 +35,6 @@ class NewInvoiceTest < ActionDispatch::IntegrationTest assert_text 'Pay invoice' end - def test_create_new_invoices_and_display_a_list_of_them - visit registrar_invoices_path - click_link_or_button 'Add deposit' - fill_in 'Amount', with: '200.00' - fill_in 'Description', with: 'My first invoice' - click_link_or_button 'Add' - - visit registrar_invoices_path - click_link_or_button 'Add deposit' - fill_in 'Amount', with: '300.00' - fill_in 'Description', with: 'My second invoice' - click_link_or_button 'Add' - - visit registrar_invoices_path - assert_text "Unpaid", count: 2 - assert_text "Invoice no. 131050" - assert_text "Invoice no. 131051" - assert_text "240,00" - assert_text "360,00" - end - # This test case should fail once issue #651 gets fixed def test_create_new_invoice_with_amount_0_goes_through visit registrar_invoices_path diff --git a/test/models/payments/bank_link_test.rb b/test/models/payments/bank_link_test.rb index 14ec2b6cb..5297a530d 100644 --- a/test/models/payments/bank_link_test.rb +++ b/test/models/payments/bank_link_test.rb @@ -3,15 +3,6 @@ require 'test_helper' class BankLinkTest < ActiveSupport::TestCase def setup super - - @original_methods = ENV['payment_methods'] - @original_seb_URL = ENV['seb_payment_url'] - ENV['payment_methods'] = 'seb, swed, credit_card' - ENV['seb_payment_url'] = 'https://example.com/seb_url' - ENV['seb_seller_account'] = 'SEB' - ENV['seb_bank_certificate'] = 'test/fixtures/files/seb_bank_cert.pem' - ENV['seb_seller_certificate'] = 'test/fixtures/files/seb_seller_key.pem' - @invoice = invoices(:valid) params = {return_url: 'return.url', response_url: 'response_url'} @bank_link = Payments::BankLink.new('seb', @invoice, params) @@ -21,9 +12,6 @@ class BankLinkTest < ActiveSupport::TestCase def teardown super - - ENV['payment_methods'] = @original_methods - ENV['seb_payment_url'] = @original_seb_URL travel_back end