From 96caf6f4d0977a98626d080959deabca550518a0 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 16:48:19 +0200 Subject: [PATCH 01/12] =?UTF-8?q?=D0=97=D0=B0=D0=BC=D0=B5=D0=BD=D0=B8?= =?UTF-8?q?=D1=82=D1=8C=20class=20reopening=20=D0=BD=D0=B0=20=D0=B2=D0=BB?= =?UTF-8?q?=D0=BE=D0=B6=D0=B5=D0=BD=D0=BD=D1=83=D1=8E=20=D1=81=D1=82=D1=80?= =?UTF-8?q?=D1=83=D0=BA=D1=82=D1=83=D1=80=D1=83=20=D0=BC=D0=BE=D0=B4=D1=83?= =?UTF-8?q?=D0=BB=D0=B5=D0=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- lib/payment_services/adv_cash/client.rb | 157 +++++------ lib/payment_services/adv_cash/invoice.rb | 33 ++- lib/payment_services/adv_cash/invoicer.rb | 87 +++--- lib/payment_services/adv_cash/payout.rb | 85 +++--- .../adv_cash/payout_adapter.rb | 83 +++--- lib/payment_services/ali_kassa/client.rb | 155 ++++++----- lib/payment_services/ali_kassa/invoice.rb | 49 ++-- lib/payment_services/ali_kassa/invoicer.rb | 151 +++++----- .../ali_kassa_peer_to_peer/invoice.rb | 49 ++-- .../ali_kassa_peer_to_peer/invoicer.rb | 87 +++--- lib/payment_services/any_money/client.rb | 159 +++++------ lib/payment_services/any_money/invoice.rb | 49 ++-- lib/payment_services/any_money/invoicer.rb | 105 +++---- lib/payment_services/any_money/payout.rb | 55 ++-- .../any_money/payout_adapter.rb | 91 +++--- lib/payment_services/any_pay/client.rb | 167 +++++------ lib/payment_services/any_pay/invoice.rb | 27 +- lib/payment_services/any_pay/invoicer.rb | 99 +++---- lib/payment_services/any_pay/payout.rb | 27 +- .../any_pay/payout_adapter.rb | 91 +++--- lib/payment_services/appex_money/client.rb | 191 ++++++------- lib/payment_services/appex_money/payout.rb | 55 ++-- .../appex_money/payout_adapter.rb | 111 ++++---- lib/payment_services/best_api/client.rb | 33 ++- lib/payment_services/best_api/invoice.rb | 27 +- lib/payment_services/best_api/invoicer.rb | 51 ++-- lib/payment_services/binance/client.rb | 105 +++---- lib/payment_services/binance/invoice.rb | 77 +++--- lib/payment_services/binance/invoicer.rb | 107 +++---- lib/payment_services/binance/payout.rb | 111 ++++---- .../binance/payout_adapter.rb | 97 +++---- lib/payment_services/block_io/client.rb | 117 ++++---- lib/payment_services/block_io/invoice.rb | 69 ++--- lib/payment_services/block_io/invoicer.rb | 101 +++---- lib/payment_services/block_io/payout.rb | 69 ++--- .../block_io/payout_adapter.rb | 163 +++++------ lib/payment_services/block_io/transaction.rb | 67 ++--- lib/payment_services/blockchair/blockchain.rb | 133 ++++----- lib/payment_services/blockchair/client.rb | 73 ++--- lib/payment_services/blockchair/invoice.rb | 25 +- lib/payment_services/blockchair/invoicer.rb | 113 ++++---- .../blockchair/transaction.rb | 169 ++++++------ .../blockchair/transaction_matcher.rb | 261 +++++++++--------- lib/payment_services/bovapay/client.rb | 101 +++---- lib/payment_services/bovapay/invoice.rb | 27 +- lib/payment_services/bovapay/invoicer.rb | 113 ++++---- lib/payment_services/bovapay/payout.rb | 27 +- .../bovapay/payout_adapter.rb | 93 ++++--- lib/payment_services/bridgex/client.rb | 85 +++--- lib/payment_services/bridgex/invoice.rb | 27 +- lib/payment_services/bridgex/invoicer.rb | 145 +++++----- .../coin_payments_hub/client.rb | 97 +++---- .../coin_payments_hub/currency_repository.rb | 59 ++-- .../coin_payments_hub/invoice.rb | 45 +-- .../coin_payments_hub/invoicer.rb | 103 +++---- .../coin_payments_hub/transaction.rb | 71 ++--- .../crypto_apis/clients/base_client.rb | 141 +++++----- .../crypto_apis/clients/dash_client.rb | 15 +- .../crypto_apis/clients/ethereum_client.rb | 19 +- .../crypto_apis/clients/omni_client.rb | 15 +- lib/payment_services/crypto_apis/invoice.rb | 67 ++--- lib/payment_services/crypto_apis/invoicer.rb | 177 ++++++------ lib/payment_services/crypto_apis/payout.rb | 61 ++-- .../crypto_apis/payout_adapter.rb | 113 ++++---- .../crypto_apis/payout_clients/base_client.rb | 93 ++++--- .../crypto_apis/payout_clients/dash_client.rb | 31 ++- .../payout_clients/ethereum_client.rb | 57 ++-- .../crypto_apis/payout_clients/omni_client.rb | 57 ++-- .../crypto_apis_v2/blockchain.rb | 157 +++++------ lib/payment_services/crypto_apis_v2/client.rb | 243 ++++++++-------- .../crypto_apis_v2/invoice.rb | 83 +++--- .../crypto_apis_v2/invoicer.rb | 63 +++-- lib/payment_services/crypto_apis_v2/payout.rb | 67 ++--- .../crypto_apis_v2/payout_adapter.rb | 93 ++++--- .../crypto_apis_v2/transaction.rb | 103 +++---- .../crypto_apis_v2/transaction_repository.rb | 259 ++++++++--------- lib/payment_services/cryptomus/client.rb | 119 ++++---- lib/payment_services/cryptomus/invoice.rb | 55 ++-- lib/payment_services/cryptomus/invoicer.rb | 137 ++++----- lib/payment_services/cryptomus/payout.rb | 23 +- .../cryptomus/payout_adapter.rb | 159 +++++------ lib/payment_services/erapay/client.rb | 45 +-- lib/payment_services/erapay/invoice.rb | 31 ++- lib/payment_services/erapay/invoicer.rb | 77 +++--- lib/payment_services/ex_pay/client.rb | 97 +++---- lib/payment_services/ex_pay/invoice.rb | 29 +- lib/payment_services/ex_pay/invoicer.rb | 109 ++++---- lib/payment_services/ex_pay/payout.rb | 23 +- lib/payment_services/ex_pay/payout_adapter.rb | 93 ++++--- lib/payment_services/exmo/client.rb | 107 +++---- lib/payment_services/exmo/invoice.rb | 67 ++--- lib/payment_services/exmo/invoicer.rb | 89 +++--- lib/payment_services/exmo/payout.rb | 81 +++--- lib/payment_services/exmo/payout_adapter.rb | 127 ++++----- lib/payment_services/exmo/transaction.rb | 55 ++-- lib/payment_services/ff/client.rb | 103 +++---- lib/payment_services/ff/invoice.rb | 33 ++- lib/payment_services/ff/invoicer.rb | 111 ++++---- lib/payment_services/ff/payout.rb | 31 ++- lib/payment_services/ff/payout_adapter.rb | 63 +++-- lib/payment_services/ff/transaction.rb | 71 ++--- lib/payment_services/fire_kassa/client.rb | 87 +++--- lib/payment_services/fire_kassa/invoice.rb | 27 +- lib/payment_services/fire_kassa/invoicer.rb | 127 ++++----- lib/payment_services/just_pays/client.rb | 83 +++--- lib/payment_services/just_pays/invoice.rb | 33 ++- lib/payment_services/just_pays/invoicer.rb | 99 +++---- lib/payment_services/kuna/client.rb | 171 ++++++------ lib/payment_services/kuna/invoice.rb | 83 +++--- lib/payment_services/kuna/invoicer.rb | 141 +++++----- lib/payment_services/kuna/payout.rb | 61 ++-- lib/payment_services/kuna/payout_adapter.rb | 103 +++---- lib/payment_services/liquid/client.rb | 187 +++++++------ lib/payment_services/liquid/invoice.rb | 55 ++-- lib/payment_services/liquid/invoicer.rb | 89 +++--- lib/payment_services/liquid/payout.rb | 61 ++-- lib/payment_services/liquid/payout_adapter.rb | 103 +++---- .../manual_by_group/invoicer.rb | 51 ++-- .../master_processing/client.rb | 139 +++++----- .../master_processing/invoice.rb | 67 ++--- .../master_processing/invoicer.rb | 133 ++++----- .../master_processing/payout.rb | 61 ++-- .../master_processing/payout_adapter.rb | 123 +++++---- .../master_processing/response.rb | 57 ++-- .../merchant_alikassa/client.rb | 115 ++++---- .../merchant_alikassa/invoice.rb | 27 +- .../merchant_alikassa/invoicer.rb | 109 ++++---- .../merchant_alikassa/payout.rb | 23 +- .../merchant_alikassa/payout_adapter.rb | 131 ++++----- .../merchant_alikassa_virtual/client.rb | 91 +++--- .../merchant_alikassa_virtual/invoice.rb | 27 +- .../merchant_alikassa_virtual/invoicer.rb | 95 ++++--- lib/payment_services/obmenka/client.rb | 233 ++++++++-------- lib/payment_services/obmenka/invoice.rb | 67 ++--- lib/payment_services/obmenka/invoicer.rb | 103 +++---- lib/payment_services/obmenka/payout.rb | 85 +++--- .../obmenka/payout_adapter.rb | 99 +++---- lib/payment_services/oko_otc/client.rb | 85 +++--- lib/payment_services/oko_otc/payout.rb | 71 ++--- .../oko_otc/payout_adapter.rb | 117 ++++---- lib/payment_services/one_crypto/client.rb | 101 +++---- lib/payment_services/one_crypto/invoice.rb | 55 ++-- lib/payment_services/one_crypto/invoicer.rb | 77 +++--- lib/payment_services/one_crypto/payout.rb | 15 +- .../one_crypto/payout_adapter.rb | 99 +++---- .../one_crypto/transaction.rb | 79 +++--- lib/payment_services/panda_pay/client.rb | 95 ++++--- lib/payment_services/panda_pay/invoice.rb | 27 +- lib/payment_services/panda_pay/invoicer.rb | 99 +++---- lib/payment_services/pay_for_u/client.rb | 59 ++-- lib/payment_services/pay_for_u/invoice.rb | 27 +- lib/payment_services/pay_for_u/invoicer.rb | 101 +++---- lib/payment_services/pay_for_u_h2h/client.rb | 53 ++-- lib/payment_services/pay_for_u_h2h/invoice.rb | 9 +- .../pay_for_u_h2h/invoicer.rb | 189 ++++++------- lib/payment_services/paycraft/client.rb | 101 +++---- lib/payment_services/paycraft/invoice.rb | 27 +- lib/payment_services/paycraft/invoicer.rb | 109 ++++---- lib/payment_services/paycraft/payout.rb | 27 +- .../paycraft/payout_adapter.rb | 97 +++---- .../paycraft_virtual/client.rb | 81 +++--- .../paycraft_virtual/invoice.rb | 27 +- .../paycraft_virtual/invoicer.rb | 97 +++---- lib/payment_services/payeer/client.rb | 165 +++++------ lib/payment_services/payeer/invoice.rb | 21 +- lib/payment_services/payeer/invoicer.rb | 87 +++--- lib/payment_services/payeer/payout.rb | 85 +++--- lib/payment_services/payeer/payout_adapter.rb | 77 +++--- lib/payment_services/paylama/client.rb | 147 +++++----- .../paylama/currency_repository.rb | 71 ++--- lib/payment_services/paylama/invoice.rb | 71 ++--- lib/payment_services/paylama/invoicer.rb | 117 ++++---- lib/payment_services/paylama/payout.rb | 71 ++--- .../paylama/payout_adapter.rb | 103 +++---- .../paylama_crypto/invoice.rb | 61 ++-- .../paylama_crypto/invoicer.rb | 55 ++-- lib/payment_services/paylama_crypto/payout.rb | 21 +- .../paylama_crypto/payout_adapter.rb | 97 +++---- .../paylama_crypto/transaction.rb | 103 +++---- lib/payment_services/paylama_p2p/client.rb | 21 +- lib/payment_services/paylama_p2p/invoice.rb | 9 +- lib/payment_services/paylama_p2p/invoicer.rb | 111 ++++---- lib/payment_services/paylama_sbp/client.rb | 21 +- lib/payment_services/paylama_sbp/invoice.rb | 27 +- lib/payment_services/paylama_sbp/invoicer.rb | 107 +++---- lib/payment_services/perfect_money/client.rb | 207 +++++++------- lib/payment_services/perfect_money/invoice.rb | 49 ++-- .../perfect_money/invoicer.rb | 55 ++-- lib/payment_services/perfect_money/payout.rb | 63 +++-- .../perfect_money/payout_adapter.rb | 57 ++-- lib/payment_services/qiwi/client.rb | 237 ++++++++-------- lib/payment_services/qiwi/importer.rb | 133 ++++----- lib/payment_services/qiwi/invoice.rb | 7 +- lib/payment_services/qiwi/invoicer.rb | 47 ++-- lib/payment_services/qiwi/payment.rb | 29 +- lib/payment_services/qiwi/payout_adapter.rb | 47 ++-- lib/payment_services/rbk/client.rb | 105 +++---- lib/payment_services/rbk/customer.rb | 147 +++++----- lib/payment_services/rbk/customer_client.rb | 93 ++++--- lib/payment_services/rbk/identity.rb | 49 ++-- lib/payment_services/rbk/identity_client.rb | 29 +- lib/payment_services/rbk/invoice.rb | 135 ++++----- lib/payment_services/rbk/invoice_client.rb | 95 ++++--- lib/payment_services/rbk/invoicer.rb | 95 ++++--- lib/payment_services/rbk/payment.rb | 139 +++++----- lib/payment_services/rbk/payment_card.rb | 19 +- lib/payment_services/rbk/payment_client.rb | 67 ++--- lib/payment_services/rbk/payout.rb | 79 +++--- lib/payment_services/rbk/payout_adapter.rb | 53 ++-- lib/payment_services/rbk/payout_client.rb | 43 +-- .../rbk/payout_destination.rb | 93 ++++--- .../rbk/payout_destination_client.rb | 73 ++--- lib/payment_services/rbk/wallet.rb | 23 +- lib/payment_services/rbk/wallet_client.rb | 29 +- lib/payment_services/transfera/client.rb | 77 +++--- lib/payment_services/transfera/invoice.rb | 27 +- lib/payment_services/transfera/invoicer.rb | 99 +++---- lib/payment_services/tronscan/client.rb | 73 ++--- lib/payment_services/tronscan/invoice.rb | 19 +- lib/payment_services/tronscan/invoicer.rb | 57 ++-- lib/payment_services/tronscan/transaction.rb | 39 +-- .../tronscan/transaction_matcher.rb | 99 +++---- lib/payment_services/wallex/client.rb | 117 ++++---- lib/payment_services/wallex/invoice.rb | 27 +- lib/payment_services/wallex/invoicer.rb | 103 +++---- lib/payment_services/wallex/payout.rb | 27 +- lib/payment_services/wallex/payout_adapter.rb | 93 ++++--- lib/payment_services/x_pay_pro/client.rb | 59 ++-- lib/payment_services/x_pay_pro/invoice.rb | 27 +- lib/payment_services/x_pay_pro/invoicer.rb | 109 ++++---- .../x_pay_pro_virtual/client.rb | 59 ++-- .../x_pay_pro_virtual/invoice.rb | 27 +- .../x_pay_pro_virtual/invoicer.rb | 109 ++++---- lib/payment_services/yandex_money/invoice.rb | 7 +- lib/payment_services/yandex_money/invoicer.rb | 41 +-- .../yandex_money_payment_card/invoice.rb | 7 +- .../yandex_money_payment_card/invoicer.rb | 41 +-- lib/payment_services/your_payments/client.rb | 123 +++++---- lib/payment_services/your_payments/invoice.rb | 27 +- .../your_payments/invoicer.rb | 159 +++++------ lib/payment_services/your_payments/payout.rb | 23 +- .../your_payments/payout_adapter.rb | 111 ++++---- 242 files changed, 10350 insertions(+), 9624 deletions(-) diff --git a/lib/payment_services/adv_cash/client.rb b/lib/payment_services/adv_cash/client.rb index c5242b25..bf28d78c 100644 --- a/lib/payment_services/adv_cash/client.rb +++ b/lib/payment_services/adv_cash/client.rb @@ -2,96 +2,99 @@ require 'savon' -class PaymentServices::AdvCash - class Client - include AutoLogger - TIMEOUT = 10 - SOAP_URL = 'https://account.volet.com/wsm/apiWebService?wsdl' - - def initialize(api_name:, authentication_token:, account_email:) - @api_name = api_name - @authentication_token = authentication_token - @account_email = account_email - end - def create_invoice(params:) - safely_parse soap_request( - url: SOAP_URL, - operation: :create_p2p_order, - body: { - arg0: authentication_params, - arg1: params - } - ) - end +module PaymentServices + class AdvCash + class Client + include AutoLogger + TIMEOUT = 10 + SOAP_URL = 'https://account.volet.com/wsm/apiWebService?wsdl' - def find_invoice(deposit_id:) - safely_parse soap_request( - url: SOAP_URL, - operation: :find_p2p_order_by_order_id, - body: { - arg0: authentication_params, - arg1: deposit_id - } - ) - end + def initialize(api_name:, authentication_token:, account_email:) + @api_name = api_name + @authentication_token = authentication_token + @account_email = account_email + end - def create_payout(params:) - safely_parse soap_request( - url: SOAP_URL, - operation: :send_money, - body: { - arg0: authentication_params, - arg1: params - } - ) - end + def create_invoice(params:) + safely_parse soap_request( + url: SOAP_URL, + operation: :create_p2p_order, + body: { + arg0: authentication_params, + arg1: params + } + ) + end - def find_transaction(id:) - safely_parse soap_request( - url: SOAP_URL, - operation: :find_transaction, - body: { - arg0: authentication_params, - arg1: id - } - ) - end + def find_invoice(deposit_id:) + safely_parse soap_request( + url: SOAP_URL, + operation: :find_p2p_order_by_order_id, + body: { + arg0: authentication_params, + arg1: deposit_id + } + ) + end - private + def create_payout(params:) + safely_parse soap_request( + url: SOAP_URL, + operation: :send_money, + body: { + arg0: authentication_params, + arg1: params + } + ) + end - attr_reader :api_name, :authentication_token, :account_email + def find_transaction(id:) + safely_parse soap_request( + url: SOAP_URL, + operation: :find_transaction, + body: { + arg0: authentication_params, + arg1: id + } + ) + end - def encrypted_token - sign_string = "#{authentication_token}:#{Time.now.utc.strftime('%Y%m%d:%H')}" + private - Digest::SHA256.hexdigest(sign_string).upcase - end + attr_reader :api_name, :authentication_token, :account_email - def soap_request(url:, operation:, body:) - logger.info "Request operation: #{operation} to #{url} with payload #{body}" + def encrypted_token + sign_string = "#{authentication_token}:#{Time.now.utc.strftime('%Y%m%d:%H')}" - Savon.client(wsdl: url, open_timeout: TIMEOUT, read_timeout: TIMEOUT).call(operation, message: body) - end + Digest::SHA256.hexdigest(sign_string).upcase + end + + def soap_request(url:, operation:, body:) + logger.info "Request operation: #{operation} to #{url} with payload #{body}" - def safely_parse(response) - res = response.body - logger.info "Response: #{res}" - res - rescue Savon::SOAPFault => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + Savon.client(wsdl: url, open_timeout: TIMEOUT, read_timeout: TIMEOUT).call(operation, message: body) + end + + def safely_parse(response) + res = response.body + logger.info "Response: #{res}" + res + rescue Savon::SOAPFault => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body - end - def authentication_params - { - apiName: api_name, - authenticationToken: encrypted_token, - accountEmail: account_email - } + def authentication_params + { + apiName: api_name, + authenticationToken: encrypted_token, + accountEmail: account_email + } + end end end end diff --git a/lib/payment_services/adv_cash/invoice.rb b/lib/payment_services/adv_cash/invoice.rb index 0635b528..17148213 100644 --- a/lib/payment_services/adv_cash/invoice.rb +++ b/lib/payment_services/adv_cash/invoice.rb @@ -2,27 +2,30 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::AdvCash - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'COMPLETED' - FAILED_PROVIDER_STATES = %w(EXPIRED CANCELED) - self.table_name = 'adv_cash_invoices' +module PaymentServices + class AdvCash + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'COMPLETED' + FAILED_PROVIDER_STATES = %w(EXPIRED CANCELED) - monetize :amount_cents, as: :amount + self.table_name = 'adv_cash_invoices' - def formatted_amount - format('%.2f', amount.to_f) - end + monetize :amount_cents, as: :amount - private + def formatted_amount + format('%.2f', amount.to_f) + end - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/adv_cash/invoicer.rb b/lib/payment_services/adv_cash/invoicer.rb index 0470cdb3..9c3f7cba 100644 --- a/lib/payment_services/adv_cash/invoicer.rb +++ b/lib/payment_services/adv_cash/invoicer.rb @@ -5,49 +5,52 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::AdvCash - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params).dig(:create_p2p_order_response, :return) - - invoice.update!( - deposit_id: response[:order_id], - pay_url: response[:payment_url] - ) - end - - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end - - def async_invoice_state_updater? - true - end - - def update_invoice_state! - transaction = client.find_invoice(deposit_id: invoice.deposit_id).dig(:find_p2p_order_by_order_id_response, :return) - invoice.update_state_by_provider(transaction[:status]) - end - - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end - - def invoice_params - currency = invoice.amount_currency.to_s - currency = 'RUR' if currency == 'RUB' - { - amount: invoice.formatted_amount, - currency: currency, - receiver: order.income_wallet.adv_cash_merchant_email, - orderId: order.public_id.to_s, - redirectUrl: order.success_redirect - } - end - def client - @client ||= Client.new(api_name: order.income_wallet.merchant_id, authentication_token: api_key, account_email: order.income_wallet.adv_cash_merchant_email) +module PaymentServices + class AdvCash + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params).dig(:create_p2p_order_response, :return) + + invoice.update!( + deposit_id: response[:order_id], + pay_url: response[:payment_url] + ) + end + + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end + + def async_invoice_state_updater? + true + end + + def update_invoice_state! + transaction = client.find_invoice(deposit_id: invoice.deposit_id).dig(:find_p2p_order_by_order_id_response, :return) + invoice.update_state_by_provider(transaction[:status]) + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + def invoice_params + currency = invoice.amount_currency.to_s + currency = 'RUR' if currency == 'RUB' + { + amount: invoice.formatted_amount, + currency: currency, + receiver: order.income_wallet.adv_cash_merchant_email, + orderId: order.public_id.to_s, + redirectUrl: order.success_redirect + } + end + + def client + @client ||= Client.new(api_name: order.income_wallet.merchant_id, authentication_token: api_key, account_email: order.income_wallet.adv_cash_merchant_email) + end end end end diff --git a/lib/payment_services/adv_cash/payout.rb b/lib/payment_services/adv_cash/payout.rb index 9a66d1ef..60eebfc4 100644 --- a/lib/payment_services/adv_cash/payout.rb +++ b/lib/payment_services/adv_cash/payout.rb @@ -1,56 +1,59 @@ # frozen_string_literal: true -class PaymentServices::AdvCash - class Payout < ApplicationRecord - include Workflow - self.table_name = 'advcash_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed +module PaymentServices + class AdvCash + class Payout < ApplicationRecord + include Workflow + + self.table_name = 'advcash_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - confirm! if success? - fail! if failed? - end + confirm! if success? + fail! if failed? + end - def build_note - "#{order_payout.order.public_id}-#{order_payout.id}" - end + def build_note + "#{order_payout.order.public_id}-#{order_payout.id}" + end - private + private - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) - end + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end - def success? - provider_state == 'COMPLETED' - end + def success? + provider_state == 'COMPLETED' + end - def failed? - provider_state == 'CANCELED' + def failed? + provider_state == 'CANCELED' + end end end end diff --git a/lib/payment_services/adv_cash/payout_adapter.rb b/lib/payment_services/adv_cash/payout_adapter.rb index d1d60d02..bff16372 100644 --- a/lib/payment_services/adv_cash/payout_adapter.rb +++ b/lib/payment_services/adv_cash/payout_adapter.rb @@ -3,59 +3,62 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::AdvCash - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class AdvCash + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.find_transaction(id: payout.withdrawal_id) + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - raise "Can't get withdrawal details: #{response[:exception]}" if response[:exception] + response = client.find_transaction(id: payout.withdrawal_id) - provider_state = response.dig(:find_transaction_response, :return, :status) - payout.update_state_by_provider(provider_state) if provider_state + raise "Can't get withdrawal details: #{response[:exception]}" if response[:exception] - response - end + provider_state = response.dig(:find_transaction_response, :return, :status) + payout.update_state_by_provider(provider_state) if provider_state - private + response + end - # NOTE: AdvCash использует коды 90х годов - def iso_code(currency) - actual_iso_code = currency.iso_code + private - actual_iso_code == 'RUB' ? 'RUR' : actual_iso_code - end + # NOTE: AdvCash использует коды 90х годов + def iso_code(currency) + actual_iso_code = currency.iso_code - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + actual_iso_code == 'RUB' ? 'RUR' : actual_iso_code + end - params = { - amount: amount.to_d.round(2), - currency: iso_code(wallet.currency), - walletId: destination_account, - savePaymentTemplate: false, - note: payout.build_note - } - response = client.create_payout(params: params) + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - raise "Can't process payout: #{response[:exception]}" if response[:exception] + params = { + amount: amount.to_d.round(2), + currency: iso_code(wallet.currency), + walletId: destination_account, + savePaymentTemplate: false, + note: payout.build_note + } + response = client.create_payout(params: params) - withdrawal_id = response.dig(:send_money_response, :return) - payout.pay!(withdrawal_id: withdrawal_id) if withdrawal_id - end + raise "Can't process payout: #{response[:exception]}" if response[:exception] + + withdrawal_id = response.dig(:send_money_response, :return) + payout.pay!(withdrawal_id: withdrawal_id) if withdrawal_id + end - def client - @client ||= Client.new(api_name: wallet.merchant_id, authentication_token: api_key, account_email: wallet.adv_cash_merchant_email) + def client + @client ||= Client.new(api_name: wallet.merchant_id, authentication_token: api_key, account_email: wallet.adv_cash_merchant_email) + end end end end diff --git a/lib/payment_services/ali_kassa/client.rb b/lib/payment_services/ali_kassa/client.rb index a736aa75..67065cb1 100644 --- a/lib/payment_services/ali_kassa/client.rb +++ b/lib/payment_services/ali_kassa/client.rb @@ -2,94 +2,97 @@ # Copyright (c) 2019 FINFEX https://github.com/finfex -class PaymentServices::AliKassa - class Client - include AutoLogger - TIMEOUT = 10 - API_URL = 'https://api.alikassa.com/v1/site' - MAX_INVOICE_LIVE = 18.minutes - DEFAULT_USERAGENT = 'Mozilla/5.0' - def initialize(merchant_id:, secret:) - @merchant_id = merchant_id - @secret = secret - end +module PaymentServices + class AliKassa + class Client + include AutoLogger + TIMEOUT = 10 + API_URL = 'https://api.alikassa.com/v1/site' + MAX_INVOICE_LIVE = 18.minutes + DEFAULT_USERAGENT = 'Mozilla/5.0' - def create_deposit(payment_system:, currency:, amount:, public_id:, ip:, phone:) - request_body = { - merchantUuid: merchant_id, - orderId: public_id.to_s, - phone: phone, - amount: amount.to_s, - currency: currency, - desc: I18n.t('payment_systems.default_product', order_id: public_id), - lifetime: MAX_INVOICE_LIVE.to_i, - paySystem: payment_system, - ip: ip, - userAgent: DEFAULT_USERAGENT - } + def initialize(merchant_id:, secret:) + @merchant_id = merchant_id + @secret = secret + end - safely_parse http_request( - url: "#{API_URL}/deposit", - method: :POST, - body: request_body - ) - end + def create_deposit(payment_system:, currency:, amount:, public_id:, ip:, phone:) + request_body = { + merchantUuid: merchant_id, + orderId: public_id.to_s, + phone: phone, + amount: amount.to_s, + currency: currency, + desc: I18n.t('payment_systems.default_product', order_id: public_id), + lifetime: MAX_INVOICE_LIVE.to_i, + paySystem: payment_system, + ip: ip, + userAgent: DEFAULT_USERAGENT + } - private + safely_parse http_request( + url: "#{API_URL}/deposit", + method: :POST, + body: request_body + ) + end - attr_reader :merchant_id, :secret + private - def http_request(url:, method:, body: nil, headers: {}) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body, headers: headers) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + attr_reader :merchant_id, :secret - def build_request(uri:, method:, body: nil, headers: {}) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, build_headers(headers, body)) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, build_headers(headers, body)) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + def http_request(url:, method:, body: nil, headers: {}) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body, headers: headers) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def build_request(uri:, method:, body: nil, headers: {}) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, build_headers(headers, body)) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, build_headers(headers, body)) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - def build_headers(headers, body) - { - 'Content-Type': 'application/json; charset=utf-8', - 'Cache-Control': 'no-cache', - 'Authorization': "Basic #{auth_token(body)}" - }.merge(headers) - end + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end - def auth_token(params) - sign_string = params.sort_by { |k, _v| k }.map(&:last).join(':') + ":#{secret}" - sign_hash = Digest::MD5.base64digest(sign_string) - Base64.urlsafe_encode64("#{merchant_id}:#{sign_hash}") - end + def build_headers(headers, body) + { + 'Content-Type': 'application/json; charset=utf-8', + 'Cache-Control': 'no-cache', + 'Authorization': "Basic #{auth_token(body)}" + }.merge(headers) + end + + def auth_token(params) + sign_string = params.sort_by { |k, _v| k }.map(&:last).join(':') + ":#{secret}" + sign_hash = Digest::MD5.base64digest(sign_string) + Base64.urlsafe_encode64("#{merchant_id}:#{sign_hash}") + end - def safely_parse(response) - JSON.parse(response.body) - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:alikassa, response_class: response.class, response_body: response.body) + def safely_parse(response) + JSON.parse(response.body) + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:alikassa, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/ali_kassa/invoice.rb b/lib/payment_services/ali_kassa/invoice.rb index 471e5e3f..0932a3ed 100644 --- a/lib/payment_services/ali_kassa/invoice.rb +++ b/lib/payment_services/ali_kassa/invoice.rb @@ -2,37 +2,40 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::AliKassa - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'ali_kassa_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class AliKassa + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'ali_kassa_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end end end end diff --git a/lib/payment_services/ali_kassa/invoicer.rb b/lib/payment_services/ali_kassa/invoicer.rb index 880835e4..4aec427c 100644 --- a/lib/payment_services/ali_kassa/invoicer.rb +++ b/lib/payment_services/ali_kassa/invoicer.rb @@ -5,90 +5,93 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::AliKassa - class Invoicer < ::PaymentServices::Base::Invoicer - ALIKASSA_PAYMENT_FORM_URL = 'https://sci.alikassa.com/payment' - ALIKASSA_TIME_LIMIT = 18.minute.to_i - ALIKASSA_LOCALHOST_IP = '127.0.0.1' - ALIKASSA_PAYWAY = { card: 'card', qiwi: 'qiwi', mobile: 'mobilePayment' }.freeze - def create_invoice(money) - invoice = Invoice.create!(amount: money, order_public_id: order.public_id) - # client = PaymentServices::AliKassa::Client.new( - # merchant_id: order.income_wallet.merchant_id, - # secret: order.income_wallet.api_key - # ) - # deposit = client.create_deposit( - # amount: order.invoice_money.to_f, - # public_id: order.public_id, - # payment_system: order.income_payment_system.payway&.capitalize, - # currency: invoice.amount_currency, - # ip: ip_from(order), - # phone: order.income_account - # ) - # invoice.update!(deposit_payload: deposit, pay_url: deposit.dig('return', 'payData', 'url')) - invoice - end - - def invoice_form_data - pay_way = order.income_payment_system.payway +module PaymentServices + class AliKassa + class Invoicer < ::PaymentServices::Base::Invoicer + ALIKASSA_PAYMENT_FORM_URL = 'https://sci.alikassa.com/payment' + ALIKASSA_TIME_LIMIT = 18.minute.to_i + ALIKASSA_LOCALHOST_IP = '127.0.0.1' + ALIKASSA_PAYWAY = { card: 'card', qiwi: 'qiwi', mobile: 'mobilePayment' }.freeze - invoice_params = { - merchantUuid: order.income_wallet.merchant_id, - orderId: order.public_id, - amount: order.invoice_money.to_f, - currency: order.income_money.currency.to_s, - desc: I18n.t('payment_systems.default_product', order_id: order.public_id), - lifetime: ALIKASSA_TIME_LIMIT, - payWayVia: pay_way&.upcase_first, - customerEmail: order.user.try(:email), - urlSuccess: order.success_redirect, - urlFail: order.failed_redirect - } - invoice_params = assign_additional_params(invoice_params: invoice_params, pay_way: pay_way) - invoice_params[:sign] = calculate_signature(invoice_params) + def create_invoice(money) + invoice = Invoice.create!(amount: money, order_public_id: order.public_id) + # client = PaymentServices::AliKassa::Client.new( + # merchant_id: order.income_wallet.merchant_id, + # secret: order.income_wallet.api_key + # ) + # deposit = client.create_deposit( + # amount: order.invoice_money.to_f, + # public_id: order.public_id, + # payment_system: order.income_payment_system.payway&.capitalize, + # currency: invoice.amount_currency, + # ip: ip_from(order), + # phone: order.income_account + # ) + # invoice.update!(deposit_payload: deposit, pay_url: deposit.dig('return', 'payData', 'url')) + invoice + end - { - url: ALIKASSA_PAYMENT_FORM_URL, - method: 'POST', - target: '_blank', - 'accept-charset' => 'UTF-8', - inputs: invoice_params - } - end + def invoice_form_data + pay_way = order.income_payment_system.payway - def pay_invoice_url - Invoice.find_by(order_public_id: order.public_id)&.pay_url - end + invoice_params = { + merchantUuid: order.income_wallet.merchant_id, + orderId: order.public_id, + amount: order.invoice_money.to_f, + currency: order.income_money.currency.to_s, + desc: I18n.t('payment_systems.default_product', order_id: order.public_id), + lifetime: ALIKASSA_TIME_LIMIT, + payWayVia: pay_way&.upcase_first, + customerEmail: order.user.try(:email), + urlSuccess: order.success_redirect, + urlFail: order.failed_redirect + } + invoice_params = assign_additional_params(invoice_params: invoice_params, pay_way: pay_way) + invoice_params[:sign] = calculate_signature(invoice_params) - private + { + url: ALIKASSA_PAYMENT_FORM_URL, + method: 'POST', + target: '_blank', + 'accept-charset' => 'UTF-8', + inputs: invoice_params + } + end - def assign_additional_params(invoice_params:, pay_way:) - invoice_params[:payWayOn] = 'Qiwi' if pay_way == ALIKASSA_PAYWAY[:qiwi] - invoice_params[:number] = order.income_account.gsub(/\D/, '') if pay_way == ALIKASSA_PAYWAY[:card] - if pay_way == ALIKASSA_PAYWAY[:mobile] - invoice_params[:customerPhone] = order.income_account.gsub(/\D/, '') - invoice_params[:operator] = order.income_operator + def pay_invoice_url + Invoice.find_by(order_public_id: order.public_id)&.pay_url end - invoice_params - end + private - def calculate_signature(params) - sign_string = params.sort_by { |k, _v| k }.map(&:last).join(':') - sign_string += ":#{api_key}" - Digest::MD5.base64digest(sign_string) - end + def assign_additional_params(invoice_params:, pay_way:) + invoice_params[:payWayOn] = 'Qiwi' if pay_way == ALIKASSA_PAYWAY[:qiwi] + invoice_params[:number] = order.income_account.gsub(/\D/, '') if pay_way == ALIKASSA_PAYWAY[:card] + if pay_way == ALIKASSA_PAYWAY[:mobile] + invoice_params[:customerPhone] = order.income_account.gsub(/\D/, '') + invoice_params[:operator] = order.income_operator + end + + invoice_params + end + + def calculate_signature(params) + sign_string = params.sort_by { |k, _v| k }.map(&:last).join(':') + sign_string += ":#{api_key}" + Digest::MD5.base64digest(sign_string) + end - def ip_from(user) - if order.remote_ip.present? - order.remote_ip - elsif user.last_login_from_ip_address.present? - order.user.last_login_from_ip_address - elsif user.last_ip.present? - order.user.last_ip - else - ALIKASSA_LOCALHOST_IP + def ip_from(user) + if order.remote_ip.present? + order.remote_ip + elsif user.last_login_from_ip_address.present? + order.user.last_login_from_ip_address + elsif user.last_ip.present? + order.user.last_ip + else + ALIKASSA_LOCALHOST_IP + end end end end diff --git a/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb b/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb index 83b5cf5b..a4f22e6c 100644 --- a/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb +++ b/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb @@ -2,37 +2,40 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::AliKassaPeerToPeer - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'ali_kassa_p2p_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class AliKassaPeerToPeer + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'ali_kassa_p2p_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end end end end diff --git a/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb b/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb index 916ddee2..208c5411 100644 --- a/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb +++ b/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb @@ -4,49 +4,52 @@ require_relative 'invoice' -class PaymentServices::AliKassaPeerToPeer - class Invoicer < ::PaymentServices::Base::Invoicer - ALIKASSA_PAYMENT_FORM_URL = 'https://sci.alikassa.com/payment' - ALIKASSA_RUB_CURRENCY = 'RUB' - ALIKASSA_CARD = 'card' - - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - end - - def invoice_form_data - pay_way = order.income_payment_system.payway&.capitalize - - invoice_params = { - merchantUuid: order.income_wallet.merchant_id, - orderId: order.public_id, - amount: order.invoice_money.to_f, - currency: ALIKASSA_RUB_CURRENCY, - payWayVia: pay_way, - desc: I18n.t('payment_systems.default_product', order_id: order.public_id), - customerEmail: order.user.try(:email), - urlSuccess: order.success_redirect, - urlFail: order.failed_redirect - } - invoice_params[:payWayOn] = 'Qiwi' if pay_way == 'Qiwi' - invoice_params[:number] = order.income_account.gsub(/\D/, '') if order.income_payment_system.payway == ALIKASSA_CARD - invoice_params[:sign] = calculate_signature(invoice_params) - - { - url: ALIKASSA_PAYMENT_FORM_URL, - method: 'POST', - target: '_blank', - 'accept-charset' => 'UTF-8', - inputs: invoice_params - } - end - - private - def calculate_signature(params) - sign_string = params.sort_by { |k, _v| k }.map(&:last).join(':') - sign_string += ":#{api_key}" - Digest::MD5.base64digest(sign_string) +module PaymentServices + class AliKassaPeerToPeer + class Invoicer < ::PaymentServices::Base::Invoicer + ALIKASSA_PAYMENT_FORM_URL = 'https://sci.alikassa.com/payment' + ALIKASSA_RUB_CURRENCY = 'RUB' + ALIKASSA_CARD = 'card' + + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + end + + def invoice_form_data + pay_way = order.income_payment_system.payway&.capitalize + + invoice_params = { + merchantUuid: order.income_wallet.merchant_id, + orderId: order.public_id, + amount: order.invoice_money.to_f, + currency: ALIKASSA_RUB_CURRENCY, + payWayVia: pay_way, + desc: I18n.t('payment_systems.default_product', order_id: order.public_id), + customerEmail: order.user.try(:email), + urlSuccess: order.success_redirect, + urlFail: order.failed_redirect + } + invoice_params[:payWayOn] = 'Qiwi' if pay_way == 'Qiwi' + invoice_params[:number] = order.income_account.gsub(/\D/, '') if order.income_payment_system.payway == ALIKASSA_CARD + invoice_params[:sign] = calculate_signature(invoice_params) + + { + url: ALIKASSA_PAYMENT_FORM_URL, + method: 'POST', + target: '_blank', + 'accept-charset' => 'UTF-8', + inputs: invoice_params + } + end + + private + + def calculate_signature(params) + sign_string = params.sort_by { |k, _v| k }.map(&:last).join(':') + sign_string += ":#{api_key}" + Digest::MD5.base64digest(sign_string) + end end end end diff --git a/lib/payment_services/any_money/client.rb b/lib/payment_services/any_money/client.rb index ecd73beb..2023db95 100644 --- a/lib/payment_services/any_money/client.rb +++ b/lib/payment_services/any_money/client.rb @@ -1,97 +1,100 @@ # frozen_string_literal: true -class PaymentServices::AnyMoney - class Client - include AutoLogger - TIMEOUT = 10 - API_URL = 'https://api.any.money/' - API_VERSION = '2.0' - - def initialize(merchant_id:, api_key:) - @merchant_id = merchant_id - @api_key = api_key - end - def create(params:) - request_for('payout.create', params) - end +module PaymentServices + class AnyMoney + class Client + include AutoLogger + TIMEOUT = 10 + API_URL = 'https://api.any.money/' + API_VERSION = '2.0' - def get(params:) - request_for('payout.get', params) - end + def initialize(merchant_id:, api_key:) + @merchant_id = merchant_id + @api_key = api_key + end - private + def create(params:) + request_for('payout.create', params) + end - attr_reader :merchant_id, :api_key + def get(params:) + request_for('payout.get', params) + end - def request_for(method, params) - safely_parse http_request( - url: API_URL, - method: :POST, - body: { - 'method': method, - 'params': params, - 'jsonrpc': API_VERSION, - 'id': '1' - } - ) - end + private - def http_request(url:, method:, body: nil) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + attr_reader :merchant_id, :api_key - def build_request(uri:, method:, body: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers(body[:params])) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, headers(body[:params])) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + def request_for(method, params) + safely_parse http_request( + url: API_URL, + method: :POST, + body: { + 'method': method, + 'params': params, + 'jsonrpc': API_VERSION, + 'id': '1' + } + ) + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def http_request(url:, method:, body: nil) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def headers(params) - utc_now = Time.now.to_i.to_s + def build_request(uri:, method:, body: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers(body[:params])) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, headers(body[:params])) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - { - 'Content-Type': 'application/json', - 'x-merchant': merchant_id.to_s, - 'x-signature': build_signature(params, utc_now), - 'x-utc-now-ms': utc_now - } - end + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end - def build_signature(params, utc_now) - sign_string = params.sort_by { |k, _v| k }.map(&:last).join.downcase + utc_now + def headers(params) + utc_now = Time.now.to_i.to_s - OpenSSL::HMAC.hexdigest('SHA512', api_key, sign_string) - end + { + 'Content-Type': 'application/json', + 'x-merchant': merchant_id.to_s, + 'x-signature': build_signature(params, utc_now), + 'x-utc-now-ms': utc_now + } + end + + def build_signature(params, utc_now) + sign_string = params.sort_by { |k, _v| k }.map(&:last).join.downcase + utc_now + + OpenSSL::HMAC.hexdigest('SHA512', api_key, sign_string) + end - def safely_parse(response) - res = JSON.parse(response.body).with_indifferent_access - logger.info "Response: #{res}" - res - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + def safely_parse(response) + res = JSON.parse(response.body).with_indifferent_access + logger.info "Response: #{res}" + res + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/any_money/invoice.rb b/lib/payment_services/any_money/invoice.rb index 4b574993..dd6b8e31 100644 --- a/lib/payment_services/any_money/invoice.rb +++ b/lib/payment_services/any_money/invoice.rb @@ -2,37 +2,40 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::AnyMoney - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'any_money_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class AnyMoney + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'any_money_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end end end end diff --git a/lib/payment_services/any_money/invoicer.rb b/lib/payment_services/any_money/invoicer.rb index fc67e53f..7b877995 100644 --- a/lib/payment_services/any_money/invoicer.rb +++ b/lib/payment_services/any_money/invoicer.rb @@ -4,65 +4,68 @@ require_relative 'invoice' -class PaymentServices::AnyMoney - class Invoicer < ::PaymentServices::Base::Invoicer - ANYMONEY_PAYMENT_FORM_URL = 'https://sci.any.money/invoice' - RUB_PAYWAYS = %w[qiwi] - UAH_PAYWAYS = %w[visamc visamc_p2p] - ANYMONEY_TIME_LIMIT = "1h30m" - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - end +module PaymentServices + class AnyMoney + class Invoicer < ::PaymentServices::Base::Invoicer + ANYMONEY_PAYMENT_FORM_URL = 'https://sci.any.money/invoice' + RUB_PAYWAYS = %w[qiwi] + UAH_PAYWAYS = %w[visamc visamc_p2p] + ANYMONEY_TIME_LIMIT = "1h30m" - def invoice_form_data - form_params = { - merchant: order.income_wallet.merchant_id, - externalid: order.public_id, - amount: amount, - in_curr: currency.to_s, - expiry: ANYMONEY_TIME_LIMIT, - payway: payway, - callback_url: order.income_payment_system.callback_url, - client_email: order.user&.email, - merchant_payfee: order.income_payment_system.transfer_comission_payer_shop? ? "1" : "0", - return_url: order.success_redirect, - return_url_fail: order.failed_redirect - } - { - url: ANYMONEY_PAYMENT_FORM_URL, - method: 'POST', - target: '_blank', - 'accept-charset' => 'UTF-8', - inputs: form_params.merge(sign: build_signature(form_params)) - } - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + end - def build_signature(params) - sign_string = params.sort_by { |k, _v| k }.map(&:last).join.downcase - OpenSSL::HMAC.hexdigest('SHA512', api_key, sign_string) - end + def invoice_form_data + form_params = { + merchant: order.income_wallet.merchant_id, + externalid: order.public_id, + amount: amount, + in_curr: currency.to_s, + expiry: ANYMONEY_TIME_LIMIT, + payway: payway, + callback_url: order.income_payment_system.callback_url, + client_email: order.user&.email, + merchant_payfee: order.income_payment_system.transfer_comission_payer_shop? ? "1" : "0", + return_url: order.success_redirect, + return_url_fail: order.failed_redirect + } + { + url: ANYMONEY_PAYMENT_FORM_URL, + method: 'POST', + target: '_blank', + 'accept-charset' => 'UTF-8', + inputs: form_params.merge(sign: build_signature(form_params)) + } + end - private + def build_signature(params) + sign_string = params.sort_by { |k, _v| k }.map(&:last).join.downcase + OpenSSL::HMAC.hexdigest('SHA512', api_key, sign_string) + end - def payway - @payway ||= order.income_payment_system.payway - end + private - def currency - if RUB_PAYWAYS.include?(payway) - RUB - elsif UAH_PAYWAYS.include?(payway) - UAH + def payway + @payway ||= order.income_payment_system.payway end - end - def amount - if currency == RUB - order.invoice_money - elsif currency == UAH - order.invoice_money.exchange_to(UAH) - end.to_f.to_s + def currency + if RUB_PAYWAYS.include?(payway) + RUB + elsif UAH_PAYWAYS.include?(payway) + UAH + end + end + + def amount + if currency == RUB + order.invoice_money + elsif currency == UAH + order.invoice_money.exchange_to(UAH) + end.to_f.to_s + end end end end diff --git a/lib/payment_services/any_money/payout.rb b/lib/payment_services/any_money/payout.rb index 71b67d4d..f66749da 100644 --- a/lib/payment_services/any_money/payout.rb +++ b/lib/payment_services/any_money/payout.rb @@ -1,38 +1,41 @@ # frozen_string_literal: true -class PaymentServices::AnyMoney - class Payout < ApplicationRecord - include Workflow - self.table_name = 'any_money_payouts' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class AnyMoney + class Payout < ApplicationRecord + include Workflow + self.table_name = 'any_money_payouts' - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(externalid:) - update(externalid: externalid) - end + def pay(externalid:) + update(externalid: externalid) + end - def success? - status == 'done' - end + def success? + status == 'done' + end - def status_failed? - status == 'fail' || status == 'reject' + def status_failed? + status == 'fail' || status == 'reject' + end end end end diff --git a/lib/payment_services/any_money/payout_adapter.rb b/lib/payment_services/any_money/payout_adapter.rb index ab2a1dcd..5270f2e2 100644 --- a/lib/payment_services/any_money/payout_adapter.rb +++ b/lib/payment_services/any_money/payout_adapter.rb @@ -3,62 +3,65 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::AnyMoney - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? +module PaymentServices + class AnyMoney + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - params = { - externalid: payout.externalid.to_s - } + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? - response = client.get(params: params) - raise "Can't get order details: #{response[:error][:message]}" if response.dig(:error) + params = { + externalid: payout.externalid.to_s + } - result = response[:result] - payout.update!(status: result[:status]) if result[:status] - payout.confirm! if payout.success? - payout.fail! if payout.status_failed? + response = client.get(params: params) + raise "Can't get order details: #{response[:error][:message]}" if response.dig(:error) - result - end + result = response[:result] + payout.update!(status: result[:status]) if result[:status] + payout.confirm! if payout.success? + payout.fail! if payout.status_failed? - def payout - @payout ||= Payout.find_by(id: payout_id) - end + result + end - private + def payout + @payout ||= Payout.find_by(id: payout_id) + end - attr_accessor :payout_id + private - def make_payout(amount:, destination_account:, order_payout_id:) - @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id + attr_accessor :payout_id - params = { - amount: amount.to_s, - externalid: @payout_id.to_s, - out_curr: wallet.currency.to_s.upcase, - payway: wallet.payment_system.payway, - payee: destination_account - } - response = client.create(params: params) - raise "Can't process payout: #{response[:error][:message]}" if response.dig(:error) + def make_payout(amount:, destination_account:, order_payout_id:) + @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id - result = response[:result] - payout.pay!(externalid: result[:externalid]) if result[:externalid] - end + params = { + amount: amount.to_s, + externalid: @payout_id.to_s, + out_curr: wallet.currency.to_s.upcase, + payway: wallet.payment_system.payway, + payee: destination_account + } + response = client.create(params: params) + raise "Can't process payout: #{response[:error][:message]}" if response.dig(:error) + + result = response[:result] + payout.pay!(externalid: result[:externalid]) if result[:externalid] + end - def client - @client ||= Client.new(merchant_id: wallet.merchant_id, api_key: api_key) + def client + @client ||= Client.new(merchant_id: wallet.merchant_id, api_key: api_key) + end end end end diff --git a/lib/payment_services/any_pay/client.rb b/lib/payment_services/any_pay/client.rb index c30fcac4..0cbe7e01 100644 --- a/lib/payment_services/any_pay/client.rb +++ b/lib/payment_services/any_pay/client.rb @@ -1,99 +1,102 @@ # frozen_string_literal: true -class PaymentServices::AnyPay - class Client < ::PaymentServices::Base::Client - PROJECT_ID = 11555 - API_URL = "https://anypay.io/api" - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class AnyPay + class Client < ::PaymentServices::Base::Client + PROJECT_ID = 11555 + API_URL = "https://anypay.io/api" - def create_invoice(params:) - params = { project_id: PROJECT_ID }.merge(params) - request_body = params.merge(sign: build_signature(method_name: 'create-payment', params: params)) - safely_parse(http_request( - url: "#{API_URL}/create-payment/#{secret_key}", - method: :POST, - body: request_body, - headers: build_headers - )).dig('result') - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def transaction(deposit_id:) - params = { project_id: PROJECT_ID, trans_id: deposit_id } - request_body = params.merge(sign: build_signature(method_name: 'payments', params: params)) - safely_parse(http_request( - url: "#{API_URL}/payments/#{secret_key}", - method: :POST, - body: request_body, - headers: build_headers - )).dig('result', 'payments', deposit_id) - end + def create_invoice(params:) + params = { project_id: PROJECT_ID }.merge(params) + request_body = params.merge(sign: build_signature(method_name: 'create-payment', params: params)) + safely_parse(http_request( + url: "#{API_URL}/create-payment/#{secret_key}", + method: :POST, + body: request_body, + headers: build_headers + )).dig('result') + end - def create_payout(params:) - request_body = params.merge(sign: build_payout_signature(method_name: 'create-payout', params: params)) - safely_parse(http_request( - url: "#{API_URL}/create-payout/#{secret_key}", - method: :POST, - body: request_body, - headers: build_headers - )).dig('result') - end + def transaction(deposit_id:) + params = { project_id: PROJECT_ID, trans_id: deposit_id } + request_body = params.merge(sign: build_signature(method_name: 'payments', params: params)) + safely_parse(http_request( + url: "#{API_URL}/payments/#{secret_key}", + method: :POST, + body: request_body, + headers: build_headers + )).dig('result', 'payments', deposit_id) + end - def payout(withdrawal_id:) - params = { trans_id: withdrawal_id } - request_body = params.merge(sign: build_payout_signature(method_name: 'payouts', params: params)) - safely_parse(http_request( - url: "#{API_URL}/payouts/#{secret_key}", - method: :POST, - body: request_body, - headers: build_headers - )).dig('result', 'payouts', withdrawal_id) - end + def create_payout(params:) + request_body = params.merge(sign: build_payout_signature(method_name: 'create-payout', params: params)) + safely_parse(http_request( + url: "#{API_URL}/create-payout/#{secret_key}", + method: :POST, + body: request_body, + headers: build_headers + )).dig('result') + end - private + def payout(withdrawal_id:) + params = { trans_id: withdrawal_id } + request_body = params.merge(sign: build_payout_signature(method_name: 'payouts', params: params)) + safely_parse(http_request( + url: "#{API_URL}/payouts/#{secret_key}", + method: :POST, + body: request_body, + headers: build_headers + )).dig('result', 'payouts', withdrawal_id) + end - attr_reader :api_key, :secret_key + private - def build_headers - { - 'Accept' => 'application/json', - 'Content-Type' => 'multipart/form-data' - } - end + attr_reader :api_key, :secret_key - def build_signature(method_name:, params:) - sign_string = [ - method_name, secret_key, params[:project_id], params[:pay_id], - params[:amount], params[:currency], params[:desc], params[:method], api_key - ].join - sha256_hex(sign_string) - end + def build_headers + { + 'Accept' => 'application/json', + 'Content-Type' => 'multipart/form-data' + } + end - def build_payout_signature(method_name:, params:) - sign_string = [ - method_name, secret_key, params[:payout_id], params[:payout_type], - params[:amount], params[:wallet], api_key - ].join - sha256_hex(sign_string) - end + def build_signature(method_name:, params:) + sign_string = [ + method_name, secret_key, params[:project_id], params[:pay_id], + params[:amount], params[:currency], params[:desc], params[:method], api_key + ].join + sha256_hex(sign_string) + end - def sha256_hex(sign_string) - Digest::SHA256.hexdigest(sign_string) - end + def build_payout_signature(method_name:, params:) + sign_string = [ + method_name, secret_key, params[:payout_id], params[:payout_type], + params[:amount], params[:wallet], api_key + ].join + sha256_hex(sign_string) + end + + def sha256_hex(sign_string) + Digest::SHA256.hexdigest(sign_string) + end - def build_request(uri:, method:, body: nil, headers: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, headers) - else - raise "Запрос #{method} не поддерживается!" - end - request.set_form_data(body) - request + def build_request(uri:, method:, body: nil, headers: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, headers) + else + raise "Запрос #{method} не поддерживается!" + end + request.set_form_data(body) + request + end end end end diff --git a/lib/payment_services/any_pay/invoice.rb b/lib/payment_services/any_pay/invoice.rb index 6d203272..b817a52f 100644 --- a/lib/payment_services/any_pay/invoice.rb +++ b/lib/payment_services/any_pay/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::AnyPay - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'paid' - FAILED_PROVIDER_STATES = %w(canceled expired error) - self.table_name = 'any_pay_invoices' +module PaymentServices + class AnyPay + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'paid' + FAILED_PROVIDER_STATES = %w(canceled expired error) - monetize :amount_cents, as: :amount + self.table_name = 'any_pay_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/any_pay/invoicer.rb b/lib/payment_services/any_pay/invoicer.rb index 96643915..940bcd5c 100644 --- a/lib/payment_services/any_pay/invoicer.rb +++ b/lib/payment_services/any_pay/invoicer.rb @@ -3,66 +3,69 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::AnyPay - class Invoicer < ::PaymentServices::Base::Invoicer - QIWI_PAYMENT_METHOD = 'qiwi' - CARD_PAYMENT_METHOD = 'card' - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) +module PaymentServices + class AnyPay + class Invoicer < ::PaymentServices::Base::Invoicer + QIWI_PAYMENT_METHOD = 'qiwi' + CARD_PAYMENT_METHOD = 'card' - invoice.update!( - deposit_id: response['transaction_id'], - pay_url: response['payment_url'] - ) - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end + invoice.update!( + deposit_id: response['transaction_id'], + pay_url: response['payment_url'] + ) + end - def async_invoice_state_updater? - true - end + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end - def update_invoice_state! - transaction = client.transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['status']) if transaction - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['status']) if transaction + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :income_payment_system, to: :order - delegate :currency, to: :income_payment_system + private - def invoice_params - { - pay_id: order.public_id.to_s, - amount: invoice.amount.to_f, - currency: currency.to_s, - desc: order.public_id.to_s, - method: payment_method, - email: order.user_email, - success_url: order.success_redirect, - fail_url: order.failed_redirect - } - end + delegate :income_payment_system, to: :order + delegate :currency, to: :income_payment_system - def payway - @payway ||= order.income_payment_system.payway.inquiry - end + def invoice_params + { + pay_id: order.public_id.to_s, + amount: invoice.amount.to_f, + currency: currency.to_s, + desc: order.public_id.to_s, + method: payment_method, + email: order.user_email, + success_url: order.success_redirect, + fail_url: order.failed_redirect + } + end - def payment_method - payway.qiwi? ? QIWI_PAYMENT_METHOD : CARD_PAYMENT_METHOD - end + def payway + @payway ||= order.income_payment_system.payway.inquiry + end + + def payment_method + payway.qiwi? ? QIWI_PAYMENT_METHOD : CARD_PAYMENT_METHOD + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/any_pay/payout.rb b/lib/payment_services/any_pay/payout.rb index 4faa0b0c..cb9c47a8 100644 --- a/lib/payment_services/any_pay/payout.rb +++ b/lib/payment_services/any_pay/payout.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::AnyPay - class Payout < ::PaymentServices::Base::FiatPayout - SUCCESS_PROVIDER_STATE = 'paid' - FAILED_PROVIDER_STATES = %w(canceled blocked) - self.table_name = 'any_pay_payouts' +module PaymentServices + class AnyPay + class Payout < ::PaymentServices::Base::FiatPayout + SUCCESS_PROVIDER_STATE = 'paid' + FAILED_PROVIDER_STATES = %w(canceled blocked) - monetize :amount_cents, as: :amount + self.table_name = 'any_pay_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/any_pay/payout_adapter.rb b/lib/payment_services/any_pay/payout_adapter.rb index a9c0657c..c4736ef9 100644 --- a/lib/payment_services/any_pay/payout_adapter.rb +++ b/lib/payment_services/any_pay/payout_adapter.rb @@ -3,51 +3,54 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::AnyPay - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - PAYOUT_TYPE = 'qiwi' - COMMISSION_PAYEER = 'balance' - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? - - provider_payout = client.payout(withdrawal_id: payout.withdrawal_id) - payout.update_state_by_provider(provider_payout['status']) if provider_payout - provider_payout - end - - private - - attr_reader :payout - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - - payout.pay!(withdrawal_id: response['transaction_id']) - end - - def payout_params - { - payout_id: payout.order_payout_id, - payout_type: PAYOUT_TYPE, - amount: payout.amount.to_f, - wallet: payout.destination_account[1..-1], - commission_type: COMMISSION_PAYEER - } - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class AnyPay + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + PAYOUT_TYPE = 'qiwi' + COMMISSION_PAYEER = 'balance' + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? + + provider_payout = client.payout(withdrawal_id: payout.withdrawal_id) + payout.update_state_by_provider(provider_payout['status']) if provider_payout + provider_payout + end + + private + + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + + payout.pay!(withdrawal_id: response['transaction_id']) + end + + def payout_params + { + payout_id: payout.order_payout_id, + payout_type: PAYOUT_TYPE, + amount: payout.amount.to_f, + wallet: payout.destination_account[1..-1], + commission_type: COMMISSION_PAYEER + } + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/appex_money/client.rb b/lib/payment_services/appex_money/client.rb index 0c51106c..001cc8a0 100644 --- a/lib/payment_services/appex_money/client.rb +++ b/lib/payment_services/appex_money/client.rb @@ -3,113 +3,116 @@ require 'digest' require 'securerandom' -class PaymentServices::AppexMoney - class Client - include AutoLogger - TIMEOUT = 60 - API_URL = 'https://ecommerce.appexmoney.com/api/' - - def initialize(num_ps:, first_secret_key:, second_secret_key:) - @num_ps = num_ps - @first_secret_key = first_secret_key - @second_secret_key = second_secret_key - end - def create(params:) - params = params.merge( - account: num_ps, - nonce: SecureRandom.hex(10) - ) - params[:signature] = create_signature(params) - - safely_parse http_request( - url: API_URL + 'payout/execute', - method: :POST, - body: params - ) - end +module PaymentServices + class AppexMoney + class Client + include AutoLogger + TIMEOUT = 60 + API_URL = 'https://ecommerce.appexmoney.com/api/' + + def initialize(num_ps:, first_secret_key:, second_secret_key:) + @num_ps = num_ps + @first_secret_key = first_secret_key + @second_secret_key = second_secret_key + end - def get(params:) - params = params.merge( - account: num_ps, - nonce: SecureRandom.hex(10) - ) - params[:signature] = refresh_signature(params) - - safely_parse http_request( - url: API_URL + 'payout/status', - method: :POST, - body: params - ) - end + def create(params:) + params = params.merge( + account: num_ps, + nonce: SecureRandom.hex(10) + ) + params[:signature] = create_signature(params) + + safely_parse http_request( + url: API_URL + 'payout/execute', + method: :POST, + body: params + ) + end - private + def get(params:) + params = params.merge( + account: num_ps, + nonce: SecureRandom.hex(10) + ) + params[:signature] = refresh_signature(params) + + safely_parse http_request( + url: API_URL + 'payout/status', + method: :POST, + body: params + ) + end - attr_reader :num_ps, :first_secret_key, :second_secret_key + private - def http_request(url:, method:, body: nil) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + attr_reader :num_ps, :first_secret_key, :second_secret_key - def build_request(uri:, method:, body: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, headers) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + def http_request(url:, method:, body: nil) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def headers - { - 'Content-Type': 'application/json' - } - end + def build_request(uri:, method:, body: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, headers) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def headers + { + 'Content-Type': 'application/json' + } + end - def create_signature(params) - card_number = params[:params] - masked_params = card_number[0..5] + '*' * 6 + card_number[-4..card_number.length] - sign_array = [ - params[:nonce], params[:account], params[:operator], masked_params, params[:amount], - params[:amountcurr], params[:number], first_secret_key, second_secret_key - ] + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end - Digest::MD5.hexdigest(sign_array.join(':')).upcase - end + def create_signature(params) + card_number = params[:params] + masked_params = card_number[0..5] + '*' * 6 + card_number[-4..card_number.length] + sign_array = [ + params[:nonce], params[:account], params[:operator], masked_params, params[:amount], + params[:amountcurr], params[:number], first_secret_key, second_secret_key + ] - def refresh_signature(params) - sign_array = [ - params[:nonce], params[:account], params[:number], - '', first_secret_key, second_secret_key - ] - Digest::MD5.hexdigest(sign_array.join(':')).upcase - end + Digest::MD5.hexdigest(sign_array.join(':')).upcase + end + + def refresh_signature(params) + sign_array = [ + params[:nonce], params[:account], params[:number], + '', first_secret_key, second_secret_key + ] + Digest::MD5.hexdigest(sign_array.join(':')).upcase + end - def safely_parse(response) - res = JSON.parse(response.body).with_indifferent_access - logger.info "Response: #{res}" - res - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + def safely_parse(response) + res = JSON.parse(response.body).with_indifferent_access + logger.info "Response: #{res}" + res + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/appex_money/payout.rb b/lib/payment_services/appex_money/payout.rb index 7fd090e2..4c236865 100644 --- a/lib/payment_services/appex_money/payout.rb +++ b/lib/payment_services/appex_money/payout.rb @@ -1,38 +1,41 @@ # frozen_string_literal: true -class PaymentServices::AppexMoney - class Payout < ApplicationRecord - include Workflow - self.table_name = 'appex_money_payouts' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class AppexMoney + class Payout < ApplicationRecord + include Workflow + self.table_name = 'appex_money_payouts' - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(number:) - update(number: number) - end + def pay(number:) + update(number: number) + end - def success? - status == 'OK' - end + def success? + status == 'OK' + end - def status_failed? - status == 'error' + def status_failed? + status == 'error' + end end end end diff --git a/lib/payment_services/appex_money/payout_adapter.rb b/lib/payment_services/appex_money/payout_adapter.rb index 776abe7d..d78b7450 100644 --- a/lib/payment_services/appex_money/payout_adapter.rb +++ b/lib/payment_services/appex_money/payout_adapter.rb @@ -3,71 +3,74 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::AppexMoney - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? +module PaymentServices + class AppexMoney + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.get(params: { number: number }) - raise "Can't get order details: #{response[:errortext]}" if response.dig(:errortext) + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? - payout.update!(status: response[:status]) if response[:status] - payout.confirm! if payout.success? - payout.fail! if payout.status_failed? + response = client.get(params: { number: number }) + raise "Can't get order details: #{response[:errortext]}" if response.dig(:errortext) - response - end + payout.update!(status: response[:status]) if response[:status] + payout.confirm! if payout.success? + payout.fail! if payout.status_failed? - def payout - @payout ||= Payout.find_by(id: payout_id) - end + response + end - def order_payout - @payout_number ||= OrderPayout.find(payout.order_payout_id) - end + def payout + @payout ||= Payout.find_by(id: payout_id) + end - private + def order_payout + @payout_number ||= OrderPayout.find(payout.order_payout_id) + end - attr_accessor :payout_id + private - def number - "Kassa_#{order_payout.order.public_id}_payout_#{order_payout.id}" - end + attr_accessor :payout_id - def make_payout(amount:, destination_account:, order_payout_id:) - @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id - routes_helper = Rails.application.routes.url_helpers - - params = { - amount: amount.to_d.round(2).to_s, - amountcurr: wallet.currency.to_s.upcase, - number: number, - operator: wallet.merchant_id, - params: destination_account, - callback_url: "#{routes_helper.public_public_callbacks_api_root_url}/v1/appex_money/confirm_payout" - } - response = client.create(params: params) - raise "Can't process payout: #{response[:errortext]}" if response.dig(:errortext) - - payout.pay!(number: response[:number]) if response[:number] - end + def number + "Kassa_#{order_payout.order.public_id}_payout_#{order_payout.id}" + end - def client - @client ||= begin - Client.new( - num_ps: wallet.num_ps, - first_secret_key: api_key, - second_secret_key: api_secret - ) + def make_payout(amount:, destination_account:, order_payout_id:) + @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id + routes_helper = Rails.application.routes.url_helpers + + params = { + amount: amount.to_d.round(2).to_s, + amountcurr: wallet.currency.to_s.upcase, + number: number, + operator: wallet.merchant_id, + params: destination_account, + callback_url: "#{routes_helper.public_public_callbacks_api_root_url}/v1/appex_money/confirm_payout" + } + response = client.create(params: params) + raise "Can't process payout: #{response[:errortext]}" if response.dig(:errortext) + + payout.pay!(number: response[:number]) if response[:number] + end + + def client + @client ||= begin + Client.new( + num_ps: wallet.num_ps, + first_secret_key: api_key, + second_secret_key: api_secret + ) + end end end end diff --git a/lib/payment_services/best_api/client.rb b/lib/payment_services/best_api/client.rb index 1776b1b3..5e0de37e 100644 --- a/lib/payment_services/best_api/client.rb +++ b/lib/payment_services/best_api/client.rb @@ -1,23 +1,26 @@ # frozen_string_literal: true -class PaymentServices::BestApi - class Client < ::PaymentServices::Base::Client - API_URL = 'https://nash-c6dd440834c0.herokuapp.com/api' - def initialize(api_key:) - @api_key = api_key - end +module PaymentServices + class BestApi + class Client < ::PaymentServices::Base::Client + API_URL = 'https://nash-c6dd440834c0.herokuapp.com/api' - def income_wallet(amount:, currency:) - safely_parse(http_request( - url: "#{API_URL}/get_card/client/#{api_key}/amount/#{amount}/currency/#{currency}/niche/auto", - method: :GET, - headers: {} - )).first - end + def initialize(api_key:) + @api_key = api_key + end - private + def income_wallet(amount:, currency:) + safely_parse(http_request( + url: "#{API_URL}/get_card/client/#{api_key}/amount/#{amount}/currency/#{currency}/niche/auto", + method: :GET, + headers: {} + )).first + end - attr_reader :api_key + private + + attr_reader :api_key + end end end diff --git a/lib/payment_services/best_api/invoice.rb b/lib/payment_services/best_api/invoice.rb index 8d255b30..da90dd89 100644 --- a/lib/payment_services/best_api/invoice.rb +++ b/lib/payment_services/best_api/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::BestApi - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'fully paid' - FAILED_PROVIDER_STATE = 'trade archived' - self.table_name = 'best_api_invoices' +module PaymentServices + class BestApi + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'fully paid' + FAILED_PROVIDER_STATE = 'trade archived' - monetize :amount_cents, as: :amount + self.table_name = 'best_api_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/best_api/invoicer.rb b/lib/payment_services/best_api/invoicer.rb index f96c9fd6..c2862343 100644 --- a/lib/payment_services/best_api/invoicer.rb +++ b/lib/payment_services/best_api/invoicer.rb @@ -3,36 +3,39 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::BestApi - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.income_wallet(amount: order.calculated_income_money.to_i, currency: currency.to_s) - - invoice.update!(deposit_id: response['trade']) - PaymentServices::Base::Wallet.new(address: prepare_card_number(response['card_number']), name: nil, name_group: response['trade']) - end - def create_invoice(money) - invoice - end +module PaymentServices + class BestApi + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.income_wallet(amount: order.calculated_income_money.to_i, currency: currency.to_s) - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update!(deposit_id: response['trade']) + PaymentServices::Base::Wallet.new(address: prepare_card_number(response['card_number']), name: nil, name_group: response['trade']) + end - private + def create_invoice(money) + invoice + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def client - @client ||= Client.new(api_key: api_key) - end + private + + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end + + def client + @client ||= Client.new(api_key: api_key) + end - def prepare_card_number(provider_card_number) - provider_card_number.split('|').first.split(' ').last + def prepare_card_number(provider_card_number) + provider_card_number.split('|').first.split(' ').last + end end end end diff --git a/lib/payment_services/binance/client.rb b/lib/payment_services/binance/client.rb index 0ad59fef..844f6a66 100644 --- a/lib/payment_services/binance/client.rb +++ b/lib/payment_services/binance/client.rb @@ -1,66 +1,69 @@ # frozen_string_literal: true -class PaymentServices::Binance - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.binance.com' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Binance + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.binance.com' - def deposit_history(currency:) - query = build_query(params: { coin: currency }) - safely_parse http_request( - url: "#{API_URL}/sapi/v1/capital/deposit/hisrec?#{query}", - method: :GET, - headers: build_headers - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def withdraw_history(currency:, network:) - query = build_query(params: { coin: currency, network: network }) - safely_parse http_request( - url: "#{API_URL}/sapi/v1/capital/withdraw/history?#{query}", - method: :GET, - headers: build_headers - ) - end + def deposit_history(currency:) + query = build_query(params: { coin: currency }) + safely_parse http_request( + url: "#{API_URL}/sapi/v1/capital/deposit/hisrec?#{query}", + method: :GET, + headers: build_headers + ) + end - def create_payout(params:) - query = build_query(params: params) - safely_parse http_request( - url: "#{API_URL}/sapi/v1/capital/withdraw/apply?#{query}", - method: :POST, - headers: build_headers - ) - end + def withdraw_history(currency:, network:) + query = build_query(params: { coin: currency, network: network }) + safely_parse http_request( + url: "#{API_URL}/sapi/v1/capital/withdraw/history?#{query}", + method: :GET, + headers: build_headers + ) + end - private + def create_payout(params:) + query = build_query(params: params) + safely_parse http_request( + url: "#{API_URL}/sapi/v1/capital/withdraw/apply?#{query}", + method: :POST, + headers: build_headers + ) + end - attr_reader :api_key, :secret_key + private - def build_query(params:) - query = params.merge( - timestamp: time_now_milliseconds - ).compact.to_query - query += "&signature=#{build_signature(query)}" - query - end + attr_reader :api_key, :secret_key + + def build_query(params:) + query = params.merge( + timestamp: time_now_milliseconds + ).compact.to_query + query += "&signature=#{build_signature(query)}" + query + end - def time_now_milliseconds - Time.now.to_i * 1000 - end + def time_now_milliseconds + Time.now.to_i * 1000 + end - def build_headers - { - 'Content-Type' => 'application/x-www-form-urlencoded', - 'X-MBX-APIKEY' => api_key - } - end + def build_headers + { + 'Content-Type' => 'application/x-www-form-urlencoded', + 'X-MBX-APIKEY' => api_key + } + end - def build_signature(request_body) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, request_body) + def build_signature(request_body) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, request_body) + end end end end diff --git a/lib/payment_services/binance/invoice.rb b/lib/payment_services/binance/invoice.rb index 4b1ca5ea..ffc9eca5 100644 --- a/lib/payment_services/binance/invoice.rb +++ b/lib/payment_services/binance/invoice.rb @@ -1,58 +1,61 @@ # frozen_string_literal: true -class PaymentServices::Binance - class Invoice < ApplicationRecord - include Workflow - BINANCE_SUCCESS = [1, 6] - BINANCE_FAILED = 3 +module PaymentServices + class Binance + class Invoice < ApplicationRecord + include Workflow - self.table_name = 'binance_invoices' + BINANCE_SUCCESS = [1, 6] + BINANCE_FAILED = 3 - scope :ordered, -> { order(id: :desc) } + self.table_name = 'binance_invoices' - monetize :amount_cents, as: :amount + scope :ordered, -> { order(id: :desc) } - validates :amount_cents, :order_public_id, :state, presence: true + monetize :amount_cents, as: :amount - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - pay! if success? - cancel! if failed? - end + pay! if success? + cancel! if failed? + end - def order - @order ||= Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + @order ||= Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - def token_address - order.income_payment_system.token_address.presence - end + def token_address + order.income_payment_system.token_address.presence + end - private + private - def success? - BINANCE_SUCCESS.include? provider_state - end + def success? + BINANCE_SUCCESS.include? provider_state + end - def failed? - provider_state == BINANCE_FAILED + def failed? + provider_state == BINANCE_FAILED + end end end end diff --git a/lib/payment_services/binance/invoicer.rb b/lib/payment_services/binance/invoicer.rb index 31e332f8..87fe6a46 100644 --- a/lib/payment_services/binance/invoicer.rb +++ b/lib/payment_services/binance/invoicer.rb @@ -3,75 +3,78 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Binance - class Invoicer < ::PaymentServices::Base::Invoicer - TRANSACTION_TIME_THRESHOLD = 30.minutes - DepositHistoryRequestFailed = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - end +module PaymentServices + class Binance + class Invoicer < ::PaymentServices::Base::Invoicer + TRANSACTION_TIME_THRESHOLD = 30.minutes + DepositHistoryRequestFailed = Class.new StandardError - def async_invoice_state_updater? - true - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + end - def update_invoice_state! - response = client.deposit_history(currency: invoice.amount_currency) - raise DepositHistoryRequestFailed, "Can't get deposit history: #{response['msg']}" if response.is_a? Hash + def async_invoice_state_updater? + true + end - transaction = find_transaction(transactions: response) - return if transaction.nil? + def update_invoice_state! + response = client.deposit_history(currency: invoice.amount_currency) + raise DepositHistoryRequestFailed, "Can't get deposit history: #{response['msg']}" if response.is_a? Hash - update_invoice_details(transaction: transaction) - invoice.update_state_by_provider(transaction['status']) - end + transaction = find_transaction(transactions: response) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + update_invoice_details(transaction: transaction) + invoice.update_state_by_provider(transaction['status']) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def update_invoice_details(transaction:) - invoice.transaction_id ||= transaction['txId'] - invoice.transaction_created_at ||= parse_datetime_utc(transaction['insertTime']) - invoice.save! - end + private - def parse_datetime_utc(timestamp_milliseconds) - DateTime.strptime((timestamp_milliseconds / 1000).to_i.to_s,'%s').utc - end + def update_invoice_details(transaction:) + invoice.transaction_id ||= transaction['txId'] + invoice.transaction_created_at ||= parse_datetime_utc(transaction['insertTime']) + invoice.save! + end - def find_transaction(transactions:) - transactions.find { |transaction| matches_amount_network_and_timing?(transaction) } - end + def parse_datetime_utc(timestamp_milliseconds) + DateTime.strptime((timestamp_milliseconds / 1000).to_i.to_s,'%s').utc + end - def matches_amount_network_and_timing?(transaction) - transaction['amount'].to_d == invoice.amount.to_d && match_network?(transaction) && match_time_interval?(transaction) - end + def find_transaction(transactions:) + transactions.find { |transaction| matches_amount_network_and_timing?(transaction) } + end - def match_network?(transaction) - return true unless invoice.token_address + def matches_amount_network_and_timing?(transaction) + transaction['amount'].to_d == invoice.amount.to_d && match_network?(transaction) && match_time_interval?(transaction) + end - transaction['network'] == invoice.token_address - end + def match_network?(transaction) + return true unless invoice.token_address - def match_time_interval?(transaction) - transaction_created_at_utc = parse_datetime_utc(transaction['insertTime']) - invoice_created_at_utc = invoice.created_at.utc + transaction['network'] == invoice.token_address + end - invoice_created_at_utc < transaction_created_at_utc && created_in_valid_interval?(transaction_created_at_utc, invoice_created_at_utc) - end + def match_time_interval?(transaction) + transaction_created_at_utc = parse_datetime_utc(transaction['insertTime']) + invoice_created_at_utc = invoice.created_at.utc - def created_in_valid_interval?(transaction_time, invoice_time) - interval = (transaction_time - invoice_time) - interval_in_minutes = (interval / 1.minute).round.minutes - interval_in_minutes < TRANSACTION_TIME_THRESHOLD - end + invoice_created_at_utc < transaction_created_at_utc && created_in_valid_interval?(transaction_created_at_utc, invoice_created_at_utc) + end + + def created_in_valid_interval?(transaction_time, invoice_time) + interval = (transaction_time - invoice_time) + interval_in_minutes = (interval / 1.minute).round.minutes + interval_in_minutes < TRANSACTION_TIME_THRESHOLD + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/binance/payout.rb b/lib/payment_services/binance/payout.rb index 61bdabd9..b67194f7 100644 --- a/lib/payment_services/binance/payout.rb +++ b/lib/payment_services/binance/payout.rb @@ -1,72 +1,75 @@ # frozen_string_literal: true -class PaymentServices::Binance - class Payout < ApplicationRecord - include Workflow - BINANCE_SUCCESS = 6 - BINANCE_REJECTED = 3 - BINANCE_FAILURE = 5 - - self.table_name = 'binance_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed +module PaymentServices + class Binance + class Payout < ApplicationRecord + include Workflow + + BINANCE_SUCCESS = 6 + BINANCE_REJECTED = 3 + BINANCE_FAILURE = 5 + + self.table_name = 'binance_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(withdraw_id:) - update(withdraw_id: withdraw_id) - end + def pay(withdraw_id:) + update(withdraw_id: withdraw_id) + end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - confirm! if success? - fail! if status_failed? - end + confirm! if success? + fail! if status_failed? + end - def additional_info - order.outcome_fio.presence || order.outcome_unk.presence - end + def additional_info + order.outcome_fio.presence || order.outcome_unk.presence + end - def has_additional_info? - !additional_info.nil? - end + def has_additional_info? + !additional_info.nil? + end - def token_address - order.outcome_payment_system.token_address.presence - end + def token_address + order.outcome_payment_system.token_address.presence + end - private + private - def order - @order ||= order_payout.order - end + def order + @order ||= order_payout.order + end - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) - end + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end - def success? - provider_state == BINANCE_SUCCESS - end + def success? + provider_state == BINANCE_SUCCESS + end - def status_failed? - provider_state == BINANCE_REJECTED || provider_state == BINANCE_FAILURE + def status_failed? + provider_state == BINANCE_REJECTED || provider_state == BINANCE_FAILURE + end end end end diff --git a/lib/payment_services/binance/payout_adapter.rb b/lib/payment_services/binance/payout_adapter.rb index bcb7c499..0119c568 100644 --- a/lib/payment_services/binance/payout_adapter.rb +++ b/lib/payment_services/binance/payout_adapter.rb @@ -3,65 +3,68 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Binance - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - Error = Class.new StandardError - PayoutCreateRequestFailed = Class.new Error - WithdrawHistoryRequestFailed = Class.new Error - delegate :outcome_transaction_fee_amount, to: :payment_system +module PaymentServices + class Binance + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + Error = Class.new StandardError + PayoutCreateRequestFailed = Class.new Error + WithdrawHistoryRequestFailed = Class.new Error - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end + delegate :outcome_transaction_fee_amount, to: :payment_system - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.withdraw_history(currency: payout.amount_currency, network: payout.token_address) - raise WithdrawHistoryRequestFailed, "Can't get withdraw history: #{response['msg']}" if withdraw_history_response_failed?(response) + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - transaction = response.find { |t| matches?(payout: payout, transaction: t) } - payout.update_state_by_provider(transaction['status']) if transaction.present? - transaction - end + response = client.withdraw_history(currency: payout.amount_currency, network: payout.token_address) + raise WithdrawHistoryRequestFailed, "Can't get withdraw history: #{response['msg']}" if withdraw_history_response_failed?(response) - private + transaction = response.find { |t| matches?(payout: payout, transaction: t) } + payout.update_state_by_provider(transaction['status']) if transaction.present? + transaction + end - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - payout_params = { - coin: payout.amount_currency, - amount: amount.to_d + (outcome_transaction_fee_amount || 0), - address: destination_account, - network: payout.token_address - } - payout_params[:addressTag] = payout.additional_info if payout.has_additional_info? - response = client.create_payout(params: payout_params) - raise PayoutCreateRequestFailed, "Can't create payout: #{response['msg']}" if create_payout_response_failed?(response) + private - payout.pay!(withdraw_id: response['id']) - end + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + payout_params = { + coin: payout.amount_currency, + amount: amount.to_d + (outcome_transaction_fee_amount || 0), + address: destination_account, + network: payout.token_address + } + payout_params[:addressTag] = payout.additional_info if payout.has_additional_info? + response = client.create_payout(params: payout_params) + raise PayoutCreateRequestFailed, "Can't create payout: #{response['msg']}" if create_payout_response_failed?(response) - def withdraw_history_response_failed?(response) - response.is_a? Hash - end + payout.pay!(withdraw_id: response['id']) + end - def create_payout_response_failed?(response) - response['code'].present? - end + def withdraw_history_response_failed?(response) + response.is_a? Hash + end - def matches?(payout:, transaction:) - transaction['id'] == payout.withdraw_id && transaction['amount'].to_d == payout.amount.to_d - end + def create_payout_response_failed?(response) + response['code'].present? + end + + def matches?(payout:, transaction:) + transaction['id'] == payout.withdraw_id && transaction['amount'].to_d == payout.amount.to_d + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/block_io/client.rb b/lib/payment_services/block_io/client.rb index e4583623..e610a90a 100644 --- a/lib/payment_services/block_io/client.rb +++ b/lib/payment_services/block_io/client.rb @@ -4,73 +4,76 @@ require 'block_io' -class PaymentServices::BlockIo - class Client < ::PaymentServices::Base::Client - include AutoLogger - Error = Class.new StandardError - API_VERSION = 2 - API_URL = 'https://block.io/api/v2' - def initialize(api_key:, pin: '') - @api_key = api_key - @pin = pin - end +module PaymentServices + class BlockIo + class Client < ::PaymentServices::Base::Client + include AutoLogger + Error = Class.new StandardError + API_VERSION = 2 + API_URL = 'https://block.io/api/v2' - def make_payout(address:, amount:, nonce:, fee_priority:) - logger.info "---- Request payout to: #{address}, on #{amount} ----" - transaction = prepare_transaction(amount: amount, address: address, fee_priority: fee_priority) - signed_transaction = block_io_client.create_and_sign_transaction(transaction) - submit_transaction_response = block_io_client.submit_transaction(transaction_data: signed_transaction) - logger.info "---- Response: #{submit_transaction_response.to_s} ----" - submit_transaction_response - rescue Exception, StandardError => error # BlockIo uses Exceptions instead StandardError - logger.error error.to_s - raise Error, error.to_s - end + def initialize(api_key:, pin: '') + @api_key = api_key + @pin = pin + end - def prepare_transaction(amount:, address:, fee_priority:) - params = { api_key: api_key, amounts: amount, to_addresses: address, priority: fee_priority } - response = safely_parse(http_request( - url: "#{API_URL}/prepare_transaction?#{params.to_query}", - method: :GET, - headers: build_headers - )) - raise StandardError, response['data'] if response['status'] == 'fail' - response - end + def make_payout(address:, amount:, nonce:, fee_priority:) + logger.info "---- Request payout to: #{address}, on #{amount} ----" + transaction = prepare_transaction(amount: amount, address: address, fee_priority: fee_priority) + signed_transaction = block_io_client.create_and_sign_transaction(transaction) + submit_transaction_response = block_io_client.submit_transaction(transaction_data: signed_transaction) + logger.info "---- Response: #{submit_transaction_response.to_s} ----" + submit_transaction_response + rescue Exception, StandardError => error # BlockIo uses Exceptions instead StandardError + logger.error error.to_s + raise Error, error.to_s + end - def income_transactions(address) - transactions(address: address, type: :received) - end + def prepare_transaction(amount:, address:, fee_priority:) + params = { api_key: api_key, amounts: amount, to_addresses: address, priority: fee_priority } + response = safely_parse(http_request( + url: "#{API_URL}/prepare_transaction?#{params.to_query}", + method: :GET, + headers: build_headers + )) + raise StandardError, response['data'] if response['status'] == 'fail' + response + end - def outcome_transactions(address) - transactions(address: address, type: :sent) - end + def income_transactions(address) + transactions(address: address, type: :received) + end - def extract_transaction_id(response) - response.dig('data', 'txid') - end + def outcome_transactions(address) + transactions(address: address, type: :sent) + end - private + def extract_transaction_id(response) + response.dig('data', 'txid') + end - def build_headers - {} - end + private - def transactions(address:, type:) - logger.info "---- Request transactions info on #{address} ----" - transactions = block_io_client.get_transactions(type: type.to_s, addresses: address) - logger.info "---- Response: #{transactions} ----" - transactions - rescue Exception => error - logger.error error.to_s - raise Error, error.to_s - end + def build_headers + {} + end - def block_io_client - @block_io_client ||= BlockIo::Client.new(api_key: api_key, pin: pin, version: API_VERSION) - end + def transactions(address:, type:) + logger.info "---- Request transactions info on #{address} ----" + transactions = block_io_client.get_transactions(type: type.to_s, addresses: address) + logger.info "---- Response: #{transactions} ----" + transactions + rescue Exception => error + logger.error error.to_s + raise Error, error.to_s + end - attr_reader :api_key, :pin + def block_io_client + @block_io_client ||= BlockIo::Client.new(api_key: api_key, pin: pin, version: API_VERSION) + end + + attr_reader :api_key, :pin + end end end diff --git a/lib/payment_services/block_io/invoice.rb b/lib/payment_services/block_io/invoice.rb index 1222e333..1b8117e1 100644 --- a/lib/payment_services/block_io/invoice.rb +++ b/lib/payment_services/block_io/invoice.rb @@ -1,49 +1,52 @@ # frozen_string_literal: true -class PaymentServices::BlockIo - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'block_io_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class BlockIo + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'block_io_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :address, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :bind_transaction, transitions_to: :with_transaction - end - state :with_transaction do - on_entry do - order.make_reserve! + monetize :amount_cents, as: :amount + validates :amount_cents, :address, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :bind_transaction, transitions_to: :with_transaction + end + state :with_transaction do + on_entry do + order.make_reserve! + end + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled end - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - def update_invoice_details(transaction:) - bind_transaction! if pending? - update!(transaction_created_at: transaction.created_at, transaction_id: transaction.id) + def update_invoice_details(transaction:) + bind_transaction! if pending? + update!(transaction_created_at: transaction.created_at, transaction_id: transaction.id) - pay!(payload: transaction) if transaction.successful? + pay!(payload: transaction) if transaction.successful? + end end end end diff --git a/lib/payment_services/block_io/invoicer.rb b/lib/payment_services/block_io/invoicer.rb index d6cc5939..5878ed5b 100644 --- a/lib/payment_services/block_io/invoicer.rb +++ b/lib/payment_services/block_io/invoicer.rb @@ -4,71 +4,74 @@ require_relative 'client' require_relative 'transaction' -class PaymentServices::BlockIo - class Invoicer < ::PaymentServices::Base::Invoicer - TransactionsHistoryRequestFailed = Class.new StandardError - RESPONSE_SUCCESS_STATUS = 'success' - delegate :income_wallet, to: :order +module PaymentServices + class BlockIo + class Invoicer < ::PaymentServices::Base::Invoicer + TransactionsHistoryRequestFailed = Class.new StandardError + RESPONSE_SUCCESS_STATUS = 'success' - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end + delegate :income_wallet, to: :order - def async_invoice_state_updater? - true - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - def update_invoice_state! - transaction = transaction_for(invoice) - return if transaction.nil? + def async_invoice_state_updater? + true + end - invoice.update_invoice_details(transaction: transaction) - end + def update_invoice_state! + transaction = transaction_for(invoice) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update_invoice_details(transaction: transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def transaction_for(invoice) - transactions = collect_transactions_on(address: invoice.address) - raw_transaction = transactions.find(&method(:match_transaction?)) - Transaction.build_from(raw_transaction: raw_transaction) if raw_transaction - end + private - def collect_transactions_on(address:) - response = client.income_transactions(address) - response_status = response['status'] - raise TransactionsHistoryRequestFailed, response.to_s unless response_status == RESPONSE_SUCCESS_STATUS + def transaction_for(invoice) + transactions = collect_transactions_on(address: invoice.address) + raw_transaction = transactions.find(&method(:match_transaction?)) + Transaction.build_from(raw_transaction: raw_transaction) if raw_transaction + end - response['data']['txs'] - end + def collect_transactions_on(address:) + response = client.income_transactions(address) + response_status = response['status'] + raise TransactionsHistoryRequestFailed, response.to_s unless response_status == RESPONSE_SUCCESS_STATUS - def match_transaction?(transaction) - transaction_created_at = Time.at(transaction['time']).to_datetime.utc - invoice_created_at = invoice.created_at.utc - amount = parse_amount(transaction) + response['data']['txs'] + end - match_timing?(invoice_created_at, transaction_created_at) && match_amount?(amount) - end + def match_transaction?(transaction) + transaction_created_at = Time.at(transaction['time']).to_datetime.utc + invoice_created_at = invoice.created_at.utc + amount = parse_amount(transaction) - def match_timing?(invoice_created_at, transaction_created_at) - invoice_created_at < transaction_created_at - end + match_timing?(invoice_created_at, transaction_created_at) && match_amount?(amount) + end - def match_amount?(amount) - amount.to_d == invoice.amount.to_d - end + def match_timing?(invoice_created_at, transaction_created_at) + invoice_created_at < transaction_created_at + end - def parse_amount(transaction) - received = transaction['amounts_received'].find { |received| received['recipient'] == invoice.address } - received ? received['amount'] : 0 - end + def match_amount?(amount) + amount.to_d == invoice.amount.to_d + end + + def parse_amount(transaction) + received = transaction['amounts_received'].find { |received| received['recipient'] == invoice.address } + received ? received['amount'] : 0 + end - def client - @client ||= Client.new(api_key: api_key) + def client + @client ||= Client.new(api_key: api_key) + end end end end diff --git a/lib/payment_services/block_io/payout.rb b/lib/payment_services/block_io/payout.rb index 47a5635e..22adac4d 100644 --- a/lib/payment_services/block_io/payout.rb +++ b/lib/payment_services/block_io/payout.rb @@ -1,43 +1,46 @@ # frozen_string_literal: true -class PaymentServices::BlockIo - class Payout < ApplicationRecord - include Workflow - self.table_name = 'block_io_payouts' - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :address, :fee, :state, presence: true - - alias_attribute :txid, :transaction_id - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid +module PaymentServices + class BlockIo + class Payout < ApplicationRecord + include Workflow + self.table_name = 'block_io_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :address, :fee, :state, presence: true + + alias_attribute :txid, :transaction_id + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + end + state :completed + state :failed end - state :paid do - event :confirm, transitions_to: :completed - end - state :completed - state :failed - end - def pay(transaction_id:) - update(transaction_id: transaction_id) - end + def pay(transaction_id:) + update(transaction_id: transaction_id) + end - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) - end + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end - def update_payout_details!(transaction:) - update!( - transaction_created_at: transaction.created_at, - fee: transaction.total_spend - amount.to_f - ) - confirm! if transaction.successful? + def update_payout_details!(transaction:) + update!( + transaction_created_at: transaction.created_at, + fee: transaction.total_spend - amount.to_f + ) + confirm! if transaction.successful? + end end end end diff --git a/lib/payment_services/block_io/payout_adapter.rb b/lib/payment_services/block_io/payout_adapter.rb index 1711de89..134f8c0c 100644 --- a/lib/payment_services/block_io/payout_adapter.rb +++ b/lib/payment_services/block_io/payout_adapter.rb @@ -7,87 +7,90 @@ require_relative 'transaction' # Сервис выплаты на BlockIo. Выполняет запрос на BlockIo-Клиент. # -class PaymentServices::BlockIo - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - MIN_PAYOUT_AMOUNT = 0.00002 # Block.io restriction - ALLOWED_CURRENCIES = %w(btc ltc doge).freeze - DEFAULT_FEE_PRIORITY = 'medium' - BTC_FEE_PRIORITY = 'medium' - Error = Class.new StandardError - TansactionIdNotReceived = Class.new Error - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - amount_currency = amount.currency.to_s.downcase - raise "Можно делать выплаты только в #{ALLOWED_CURRENCIES.join(', ')}" unless ALLOWED_CURRENCIES.include?(amount_currency) - raise "Кошелек должен быть в #{ALLOWED_CURRENCIES.join(', ')}" unless ALLOWED_CURRENCIES.include?(wallet_currency) - raise 'Валюты должны совпадать' unless amount_currency == wallet_currency - raise "Минимальная выплата #{MIN_PAYOUT_AMOUNT}, к выплате #{amount}" if amount.to_f < MIN_PAYOUT_AMOUNT - - make_payout( - amount: amount, - payment_card_details: payment_card_details, - transaction_id: transaction_id, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? || payout.transaction_id.nil? - - transaction = build_transaction(payout) - payout.update_payout_details!(transaction: transaction) - transaction - end - - def payout - @payout ||= Payout.find_by(id: payout_id) - end - - private - - attr_accessor :payout_id - - def make_payout(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - payout = create_payout!(amount: amount, address: destination_account, order_payout_id: order_payout_id) - response = client.make_payout( - address: destination_account, - amount: amount.format(decimal_mark: '.', symbol: nil, thousands_separator: ''), - nonce: transaction_id, - fee_priority: fee_priority - ) - transaction_id = client.extract_transaction_id(response) - raise TansactionIdNotReceived, response.to_s unless transaction_id - - payout.pay!(transaction_id: transaction_id) - end - - def find_transaction(txid:, transactions:) - transactions.find { |transaction| transaction['txid'] == txid } - end - - def create_payout!(amount:, address:, order_payout_id:) - Payout.create!(amount: amount, address: address, order_payout_id: order_payout_id) - end - - def build_transaction(payout) - wallet_transactions = client.outcome_transactions(address: wallet.account)['data']['txs'] - raw_transaction = find_transaction(txid: payout.transaction_id, transactions: wallet_transactions) - - Transaction.build_from(raw_transaction: raw_transaction.merge('currency' => payout.amount_currency.downcase)) - end - - def fee_priority - DEFAULT_FEE_PRIORITY - end - - def wallet_currency - @wallet_currency ||= wallet.currency.to_s.downcase.inquiry - end - def client - @client ||= Client.new(api_key: api_key, pin: api_secret) +module PaymentServices + class BlockIo + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + MIN_PAYOUT_AMOUNT = 0.00002 # Block.io restriction + ALLOWED_CURRENCIES = %w(btc ltc doge).freeze + DEFAULT_FEE_PRIORITY = 'medium' + BTC_FEE_PRIORITY = 'medium' + Error = Class.new StandardError + TansactionIdNotReceived = Class.new Error + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + amount_currency = amount.currency.to_s.downcase + raise "Можно делать выплаты только в #{ALLOWED_CURRENCIES.join(', ')}" unless ALLOWED_CURRENCIES.include?(amount_currency) + raise "Кошелек должен быть в #{ALLOWED_CURRENCIES.join(', ')}" unless ALLOWED_CURRENCIES.include?(wallet_currency) + raise 'Валюты должны совпадать' unless amount_currency == wallet_currency + raise "Минимальная выплата #{MIN_PAYOUT_AMOUNT}, к выплате #{amount}" if amount.to_f < MIN_PAYOUT_AMOUNT + + make_payout( + amount: amount, + payment_card_details: payment_card_details, + transaction_id: transaction_id, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? || payout.transaction_id.nil? + + transaction = build_transaction(payout) + payout.update_payout_details!(transaction: transaction) + transaction + end + + def payout + @payout ||= Payout.find_by(id: payout_id) + end + + private + + attr_accessor :payout_id + + def make_payout(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + payout = create_payout!(amount: amount, address: destination_account, order_payout_id: order_payout_id) + response = client.make_payout( + address: destination_account, + amount: amount.format(decimal_mark: '.', symbol: nil, thousands_separator: ''), + nonce: transaction_id, + fee_priority: fee_priority + ) + transaction_id = client.extract_transaction_id(response) + raise TansactionIdNotReceived, response.to_s unless transaction_id + + payout.pay!(transaction_id: transaction_id) + end + + def find_transaction(txid:, transactions:) + transactions.find { |transaction| transaction['txid'] == txid } + end + + def create_payout!(amount:, address:, order_payout_id:) + Payout.create!(amount: amount, address: address, order_payout_id: order_payout_id) + end + + def build_transaction(payout) + wallet_transactions = client.outcome_transactions(address: wallet.account)['data']['txs'] + raw_transaction = find_transaction(txid: payout.transaction_id, transactions: wallet_transactions) + + Transaction.build_from(raw_transaction: raw_transaction.merge('currency' => payout.amount_currency.downcase)) + end + + def fee_priority + DEFAULT_FEE_PRIORITY + end + + def wallet_currency + @wallet_currency ||= wallet.currency.to_s.downcase.inquiry + end + + def client + @client ||= Client.new(api_key: api_key, pin: api_secret) + end end end end diff --git a/lib/payment_services/block_io/transaction.rb b/lib/payment_services/block_io/transaction.rb index 668df1e3..f7dcc71e 100644 --- a/lib/payment_services/block_io/transaction.rb +++ b/lib/payment_services/block_io/transaction.rb @@ -1,43 +1,46 @@ # frozen_string_literal: true -class PaymentServices::BlockIo - class Transaction - include Virtus.model - - CONFIRMATIONS_FOR_COMPLETE = 1 - - attribute :id, String - attribute :confirmations, Integer - attribute :source, String - - def self.build_from(raw_transaction:) - new( - id: raw_transaction['txid'], - confirmations: raw_transaction['confirmations'], - source: raw_transaction - ) - end - def to_s - source.to_s - end +module PaymentServices + class BlockIo + class Transaction + include Virtus.model - def successful? - currency_btc? || confirmations >= CONFIRMATIONS_FOR_COMPLETE - end + CONFIRMATIONS_FOR_COMPLETE = 1 - def created_at - Time.at(source['time']).to_datetime.utc - end + attribute :id, String + attribute :confirmations, Integer + attribute :source, String - def total_spend - source['total_amount_sent'].to_f - end + def self.build_from(raw_transaction:) + new( + id: raw_transaction['txid'], + confirmations: raw_transaction['confirmations'], + source: raw_transaction + ) + end + + def to_s + source.to_s + end + + def successful? + currency_btc? || confirmations >= CONFIRMATIONS_FOR_COMPLETE + end + + def created_at + Time.at(source['time']).to_datetime.utc + end + + def total_spend + source['total_amount_sent'].to_f + end - private + private - def currency_btc? - source['currency'] == 'btc' + def currency_btc? + source['currency'] == 'btc' + end end end end diff --git a/lib/payment_services/blockchair/blockchain.rb b/lib/payment_services/blockchair/blockchain.rb index b5a9d1c8..74fa0ec9 100644 --- a/lib/payment_services/blockchair/blockchain.rb +++ b/lib/payment_services/blockchair/blockchain.rb @@ -1,83 +1,86 @@ # frozen_string_literal: true -class PaymentServices::Blockchair - class Blockchain - API_URL = 'https://api.blockchair.com' - CURRENCY_TO_BLOCKCHAIN = { - btc: 'bitcoin', - bch: 'bitcoin_cash', - ltc: 'litecoin', - doge: 'dogecoin', - dsh: 'dash', - zec: 'zcash', - eth: 'ethereum', - ada: 'cardano', - xlm: 'stellar', - xrp: 'ripple', - eos: 'eos', - usdt: 'erc_20' - }.freeze - USDT_ERC_CONTRACT_ADDRESS = '0xdac17f958d2ee523a2206206994597c13d831ec7' - BLOCKCHAIN_TO_AMOUNT_DIVIDER = { - 'ethereum' => 1e+18, - 'cardano' => 1e+6, - 'ripple' => 1e+6, - 'erc_20' => 1e+6, - }.freeze - DEFAULT_AMOUNT_DIVIDER = 1e+8 - delegate :ethereum?, :cardano?, :stellar?, :ripple?, :eos?, :erc_20?, to: :blockchain +module PaymentServices + class Blockchair + class Blockchain + API_URL = 'https://api.blockchair.com' + CURRENCY_TO_BLOCKCHAIN = { + btc: 'bitcoin', + bch: 'bitcoin_cash', + ltc: 'litecoin', + doge: 'dogecoin', + dsh: 'dash', + zec: 'zcash', + eth: 'ethereum', + ada: 'cardano', + xlm: 'stellar', + xrp: 'ripple', + eos: 'eos', + usdt: 'erc_20' + }.freeze + USDT_ERC_CONTRACT_ADDRESS = '0xdac17f958d2ee523a2206206994597c13d831ec7' + BLOCKCHAIN_TO_AMOUNT_DIVIDER = { + 'ethereum' => 1e+18, + 'cardano' => 1e+6, + 'ripple' => 1e+6, + 'erc_20' => 1e+6, + }.freeze + DEFAULT_AMOUNT_DIVIDER = 1e+8 - def initialize(currency:) - @currency = currency - end + delegate :ethereum?, :cardano?, :stellar?, :ripple?, :eos?, :erc_20?, to: :blockchain - def name - blockchain - end + def initialize(currency:) + @currency = currency + end - def transactions_endpoint(address) - if cardano? - "#{blockchain_base_api}/raw/address/#{address}" - elsif stellar? - "#{raw_account_base_url(address)}?payments=true&account=false" - elsif ripple? - "#{raw_account_base_url(address)}?transactions=true" - elsif eos? - "#{raw_account_base_url(address)}?actions=true" - elsif erc_20? - "#{API_URL}/ethereum/erc-20/#{USDT_ERC_CONTRACT_ADDRESS}/dashboards/address/#{address}" - else - "#{blockchain_base_api}/dashboards/address/#{address}" + def name + blockchain end - end - def transactions_data_endpoint(tx_ids) - "#{blockchain_base_api}/dashboards/transactions/#{tx_ids.join(',')}" - end + def transactions_endpoint(address) + if cardano? + "#{blockchain_base_api}/raw/address/#{address}" + elsif stellar? + "#{raw_account_base_url(address)}?payments=true&account=false" + elsif ripple? + "#{raw_account_base_url(address)}?transactions=true" + elsif eos? + "#{raw_account_base_url(address)}?actions=true" + elsif erc_20? + "#{API_URL}/ethereum/erc-20/#{USDT_ERC_CONTRACT_ADDRESS}/dashboards/address/#{address}" + else + "#{blockchain_base_api}/dashboards/address/#{address}" + end + end - def amount_divider - BLOCKCHAIN_TO_AMOUNT_DIVIDER[blockchain] || DEFAULT_AMOUNT_DIVIDER - end + def transactions_data_endpoint(tx_ids) + "#{blockchain_base_api}/dashboards/transactions/#{tx_ids.join(',')}" + end - private + def amount_divider + BLOCKCHAIN_TO_AMOUNT_DIVIDER[blockchain] || DEFAULT_AMOUNT_DIVIDER + end - attr_reader :currency + private - def blockchain - @blockchain ||= CURRENCY_TO_BLOCKCHAIN[currency.to_sym].inquiry - end + attr_reader :currency - def blockchain_base_api - "#{API_URL}/#{blockchain_url}" - end + def blockchain + @blockchain ||= CURRENCY_TO_BLOCKCHAIN[currency.to_sym].inquiry + end - def raw_account_base_url(address) - "#{blockchain_base_api}/raw/account/#{address}" - end + def blockchain_base_api + "#{API_URL}/#{blockchain_url}" + end + + def raw_account_base_url(address) + "#{blockchain_base_api}/raw/account/#{address}" + end - def blockchain_url - blockchain.bitcoin_cash? ? 'bitcoin-cash' : blockchain + def blockchain_url + blockchain.bitcoin_cash? ? 'bitcoin-cash' : blockchain + end end end end diff --git a/lib/payment_services/blockchair/client.rb b/lib/payment_services/blockchair/client.rb index 277ab51f..fef57b32 100644 --- a/lib/payment_services/blockchair/client.rb +++ b/lib/payment_services/blockchair/client.rb @@ -2,42 +2,45 @@ require_relative 'blockchain' -class PaymentServices::Blockchair - class Client < ::PaymentServices::Base::Client - def initialize(api_key:, currency:) - @api_key = api_key - @blockchain = Blockchain.new(currency: currency) - end - - def transactions(address:) - safely_parse http_request( - url: "#{blockchain.transactions_endpoint(address)}#{api_suffix}", - method: :GET, - headers: build_headers - ) - end - - def transactions_data(tx_ids:) - safely_parse http_request( - url: "#{blockchain.transactions_data_endpoint(tx_ids)}#{api_suffix}", - method: :GET, - headers: build_headers - ) - end - - private - - attr_reader :api_key, :blockchain - - def api_suffix - api_key ? "?key=#{api_key}" : '' - end - def build_headers - { - 'Content-Type' => 'application/json', - 'Cache-Control' => 'no-cache' - } +module PaymentServices + class Blockchair + class Client < ::PaymentServices::Base::Client + def initialize(api_key:, currency:) + @api_key = api_key + @blockchain = Blockchain.new(currency: currency) + end + + def transactions(address:) + safely_parse http_request( + url: "#{blockchain.transactions_endpoint(address)}#{api_suffix}", + method: :GET, + headers: build_headers + ) + end + + def transactions_data(tx_ids:) + safely_parse http_request( + url: "#{blockchain.transactions_data_endpoint(tx_ids)}#{api_suffix}", + method: :GET, + headers: build_headers + ) + end + + private + + attr_reader :api_key, :blockchain + + def api_suffix + api_key ? "?key=#{api_key}" : '' + end + + def build_headers + { + 'Content-Type' => 'application/json', + 'Cache-Control' => 'no-cache' + } + end end end end diff --git a/lib/payment_services/blockchair/invoice.rb b/lib/payment_services/blockchair/invoice.rb index 9da7f328..d0d8e912 100644 --- a/lib/payment_services/blockchair/invoice.rb +++ b/lib/payment_services/blockchair/invoice.rb @@ -1,20 +1,23 @@ # frozen_string_literal: true -class PaymentServices::Blockchair - class Invoice < ::PaymentServices::Base::CryptoInvoice - self.table_name = 'blockchair_invoices' - monetize :amount_cents, as: :amount +module PaymentServices + class Blockchair + class Invoice < ::PaymentServices::Base::CryptoInvoice + self.table_name = 'blockchair_invoices' - def memo - @memo ||= order.income_wallet.memo - end + monetize :amount_cents, as: :amount + + def memo + @memo ||= order.income_wallet.memo + end - def update_invoice_details(transaction:) - bind_transaction! if pending? - update!(transaction_created_at: transaction.created_at, transaction_id: transaction.id) + def update_invoice_details(transaction:) + bind_transaction! if pending? + update!(transaction_created_at: transaction.created_at, transaction_id: transaction.id) - pay!(payload: transaction) if transaction.successful? + pay!(payload: transaction) if transaction.successful? + end end end end diff --git a/lib/payment_services/blockchair/invoicer.rb b/lib/payment_services/blockchair/invoicer.rb index 9d840c6a..84bf7fb6 100644 --- a/lib/payment_services/blockchair/invoicer.rb +++ b/lib/payment_services/blockchair/invoicer.rb @@ -5,75 +5,78 @@ require_relative 'blockchain' require_relative 'transaction_matcher' -class PaymentServices::Blockchair - class Invoicer < ::PaymentServices::Base::Invoicer - TRANSANSACTIONS_AMOUNT_TO_CHECK = 3 - TransactionsHistoryRequestFailed = Class.new StandardError - delegate :income_wallet, to: :order - delegate :currency, to: :income_wallet +module PaymentServices + class Blockchair + class Invoicer < ::PaymentServices::Base::Invoicer + TRANSANSACTIONS_AMOUNT_TO_CHECK = 3 + TransactionsHistoryRequestFailed = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end + delegate :income_wallet, to: :order + delegate :currency, to: :income_wallet - def update_invoice_state! - transaction = transaction_for(invoice) - return if transaction.nil? + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - invoice.update_invoice_details(transaction: transaction) - end + def update_invoice_state! + transaction = transaction_for(invoice) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update_invoice_details(transaction: transaction) + end - def async_invoice_state_updater? - true - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def transaction_for(invoice) - TransactionMatcher.new(invoice: invoice, transactions: collect_transactions).perform - end + def async_invoice_state_updater? + true + end - private - - def collect_transactions - if blockchain.ethereum? - blockchair_transactions_by_address(invoice.address)['calls'] - elsif blockchain.cardano? - blockchair_transactions_by_address(invoice.address)['address']['caTxList'] - elsif blockchain.stellar? - blockchair_transactions_by_address(invoice.address)['payments'] - elsif blockchain.ripple? - blockchair_transactions_by_address(invoice.address)['transactions']['transactions'] - elsif blockchain.eos? - blockchair_transactions_by_address(invoice.address)['actions'] - elsif blockchain.erc_20? - blockchair_transactions_by_address(invoice.address.downcase)['transactions'] - else - transactions_data_for_address(invoice.address) + def transaction_for(invoice) + TransactionMatcher.new(invoice: invoice, transactions: collect_transactions).perform end - end - def blockchair_transactions_by_address(address) - transactions = client.transactions(address: address)['data'] - raise TransactionsHistoryRequestFailed, 'Check the payment address' unless transactions + private + + def collect_transactions + if blockchain.ethereum? + blockchair_transactions_by_address(invoice.address)['calls'] + elsif blockchain.cardano? + blockchair_transactions_by_address(invoice.address)['address']['caTxList'] + elsif blockchain.stellar? + blockchair_transactions_by_address(invoice.address)['payments'] + elsif blockchain.ripple? + blockchair_transactions_by_address(invoice.address)['transactions']['transactions'] + elsif blockchain.eos? + blockchair_transactions_by_address(invoice.address)['actions'] + elsif blockchain.erc_20? + blockchair_transactions_by_address(invoice.address.downcase)['transactions'] + else + transactions_data_for_address(invoice.address) + end + end + + def blockchair_transactions_by_address(address) + transactions = client.transactions(address: address)['data'] + raise TransactionsHistoryRequestFailed, 'Check the payment address' unless transactions - transactions[address] - end + transactions[address] + end - def transactions_data_for_address(address) - transaction_ids_on_wallet = blockchair_transactions_by_address(address)['transactions'] - client.transactions_data(tx_ids: transaction_ids_on_wallet.first(TRANSANSACTIONS_AMOUNT_TO_CHECK))['data'] - end + def transactions_data_for_address(address) + transaction_ids_on_wallet = blockchair_transactions_by_address(address)['transactions'] + client.transactions_data(tx_ids: transaction_ids_on_wallet.first(TRANSANSACTIONS_AMOUNT_TO_CHECK))['data'] + end - def blockchain - @blockchain ||= Blockchain.new(currency: currency.to_s.downcase) - end + def blockchain + @blockchain ||= Blockchain.new(currency: currency.to_s.downcase) + end - def client - @client ||= Client.new(api_key: api_key, currency: currency.to_s.downcase) + def client + @client ||= Client.new(api_key: api_key, currency: currency.to_s.downcase) + end end end end diff --git a/lib/payment_services/blockchair/transaction.rb b/lib/payment_services/blockchair/transaction.rb index 33302313..6f5766d4 100644 --- a/lib/payment_services/blockchair/transaction.rb +++ b/lib/payment_services/blockchair/transaction.rb @@ -1,111 +1,114 @@ # frozen_string_literal: true -class PaymentServices::Blockchair - class Transaction - include Virtus.model - - attribute :id, String - attribute :created_at, DateTime - attribute :blockchain, String - attribute :source, Hash - - RIPPLE_SUCCESS_STATUS = 'tesSUCCESS' - - def self.build_from(raw_transaction:) - new( - id: raw_transaction[:transaction_hash], - created_at: raw_transaction[:created_at], - blockchain: raw_transaction[:blockchain].name, - source: raw_transaction[:source].deep_symbolize_keys - ) - end - def to_s - source.to_s - end +module PaymentServices + class Blockchair + class Transaction + include Virtus.model - def successful? - send("#{blockchain}_transaction_succeed?") - end + attribute :id, String + attribute :created_at, DateTime + attribute :blockchain, String + attribute :source, Hash - def sender_address - send("#{blockchain}_sender_address") - end + RIPPLE_SUCCESS_STATUS = 'tesSUCCESS' - private + def self.build_from(raw_transaction:) + new( + id: raw_transaction[:transaction_hash], + created_at: raw_transaction[:created_at], + blockchain: raw_transaction[:blockchain].name, + source: raw_transaction[:source].deep_symbolize_keys + ) + end - def method_missing(method_name) - super unless method_name.end_with?('_transaction_succeed?') + def to_s + source.to_s + end - generic_transaction_succeed? - end + def successful? + send("#{blockchain}_transaction_succeed?") + end - def generic_transaction_succeed? - source.key?(:block_id) && source[:block_id].positive? - end + def sender_address + send("#{blockchain}_sender_address") + end - def cardano_transaction_succeed? - source.key?(:ctbFees) - end + private - def ripple_transaction_succeed? - source.dig(:meta, :TransactionResult) == RIPPLE_SUCCESS_STATUS - end + def method_missing(method_name) + super unless method_name.end_with?('_transaction_succeed?') - def stellar_transaction_succeed? - source[:transaction_successful] - end + generic_transaction_succeed? + end - def eos_transaction_succeed? - source.key?(:block_num) && source[:block_num].positive? - end + def generic_transaction_succeed? + source.key?(:block_id) && source[:block_id].positive? + end - def bitcoin_sender_address - source.dig(:input, :recipient) - end + def cardano_transaction_succeed? + source.key?(:ctbFees) + end - def bitcoin_cash_sender_address - source.dig(:input, :recipient) - end + def ripple_transaction_succeed? + source.dig(:meta, :TransactionResult) == RIPPLE_SUCCESS_STATUS + end - def litecoin_sender_address - source.dig(:input, :recipient) - end + def stellar_transaction_succeed? + source[:transaction_successful] + end - def dogecoin_sender_address - source.dig(:input, :recipient) - end + def eos_transaction_succeed? + source.key?(:block_num) && source[:block_num].positive? + end - def dash_sender_address - source.dig(:input, :recipient) - end + def bitcoin_sender_address + source.dig(:input, :recipient) + end - def zcash_sender_address - source.dig(:input, :recipient) - end + def bitcoin_cash_sender_address + source.dig(:input, :recipient) + end - def ethereum_sender_address - source[:sender] - end + def litecoin_sender_address + source.dig(:input, :recipient) + end - def cardano_sender_address - source.dig(:input, :ctaAddress, :unCAddress) - end + def dogecoin_sender_address + source.dig(:input, :recipient) + end - def stellar_sender_address - source[:from] - end + def dash_sender_address + source.dig(:input, :recipient) + end - def ripple_sender_address - source.dig(:TakerGets, :issuer) - end + def zcash_sender_address + source.dig(:input, :recipient) + end - def eos_sender_address - source[:from] - end + def ethereum_sender_address + source[:sender] + end + + def cardano_sender_address + source.dig(:input, :ctaAddress, :unCAddress) + end + + def stellar_sender_address + source[:from] + end + + def ripple_sender_address + source.dig(:TakerGets, :issuer) + end + + def eos_sender_address + source[:from] + end - def erc_20_sender_address - source[:sender] + def erc_20_sender_address + source[:sender] + end end end end diff --git a/lib/payment_services/blockchair/transaction_matcher.rb b/lib/payment_services/blockchair/transaction_matcher.rb index db882122..3865b13b 100644 --- a/lib/payment_services/blockchair/transaction_matcher.rb +++ b/lib/payment_services/blockchair/transaction_matcher.rb @@ -3,172 +3,175 @@ require_relative 'transaction' require_relative 'blockchain' -class PaymentServices::Blockchair - class TransactionMatcher - RIPPLE_AFTER_UNIX_EPOCH = 946684800 - def initialize(invoice:, transactions:) - @invoice = invoice - @transactions = transactions - end - - def perform - send("match_#{blockchain.name}_transaction") - end +module PaymentServices + class Blockchair + class TransactionMatcher + RIPPLE_AFTER_UNIX_EPOCH = 946684800 - private + def initialize(invoice:, transactions:) + @invoice = invoice + @transactions = transactions + end - attr_reader :invoice, :transactions + def perform + send("match_#{blockchain.name}_transaction") + end - delegate :created_at, :memo, to: :invoice, prefix: true - delegate :amount_divider, to: :blockchain + private - def blockchain - @blockchain ||= Blockchain.new(currency: invoice.order.income_wallet.currency.to_s.downcase) - end + attr_reader :invoice, :transactions - def build_transaction(id:, created_at:, blockchain:, source:) - Transaction.build_from(raw_transaction: { transaction_hash: id, created_at: created_at, blockchain: blockchain, source: source }) - end + delegate :created_at, :memo, to: :invoice, prefix: true + delegate :amount_divider, to: :blockchain - def match_cardano_transaction - raw_transaction = transactions.find { |transaction| match_cardano_transaction?(transaction) } - return unless raw_transaction - - inputs = raw_transaction['ctbInputs'] - output = raw_transaction['ctbOutputs'].find { |output| output.match_by_output? } - build_transaction( - id: raw_transaction['ctbId'], - created_at: timestamp_in_utc(raw_transaction['ctbTimeIssued']), - blockchain: blockchain, - source: raw_transaction.merge(input: most_similar_cardano_input_by(output: output, inputs: inputs)) - ) - end + def blockchain + @blockchain ||= Blockchain.new(currency: invoice.order.income_wallet.currency.to_s.downcase) + end - def match_stellar_transaction - raw_transaction = transactions.find { |transaction| match_stellar_transaction?(transaction) } - return unless raw_transaction + def build_transaction(id:, created_at:, blockchain:, source:) + Transaction.build_from(raw_transaction: { transaction_hash: id, created_at: created_at, blockchain: blockchain, source: source }) + end - build_transaction( - id: raw_transaction['transaction_hash'], - created_at: datetime_string_in_utc(raw_transaction['created_at']), - blockchain: blockchain, - source: raw_transaction - ) - end + def match_cardano_transaction + raw_transaction = transactions.find { |transaction| match_cardano_transaction?(transaction) } + return unless raw_transaction + + inputs = raw_transaction['ctbInputs'] + output = raw_transaction['ctbOutputs'].find { |output| output.match_by_output? } + build_transaction( + id: raw_transaction['ctbId'], + created_at: timestamp_in_utc(raw_transaction['ctbTimeIssued']), + blockchain: blockchain, + source: raw_transaction.merge(input: most_similar_cardano_input_by(output: output, inputs: inputs)) + ) + end - def match_ripple_transaction - raw_transaction = transactions.find { |transaction| match_ripple_transaction?(transaction) } - return unless raw_transaction + def match_stellar_transaction + raw_transaction = transactions.find { |transaction| match_stellar_transaction?(transaction) } + return unless raw_transaction - build_transaction( - id: raw_transaction['tx']['hash'], - created_at: build_ripple_time(raw_transaction['tx']['date']), - blockchain: blockchain, - source: raw_transaction - ) - end + build_transaction( + id: raw_transaction['transaction_hash'], + created_at: datetime_string_in_utc(raw_transaction['created_at']), + blockchain: blockchain, + source: raw_transaction + ) + end - def match_eos_transaction - raw_transaction = transactions.find { |transaction| match_eos_transaction?(transaction) } - build_transaction(id: raw_transaction['trx_id'], created_at: datetime_string_in_utc(raw_transaction['block_time']), blockchain: blockchain, source: raw_transaction) if raw_transaction - end + def match_ripple_transaction + raw_transaction = transactions.find { |transaction| match_ripple_transaction?(transaction) } + return unless raw_transaction - def method_missing(method_name) - super unless method_name.start_with?('match_') && method_name.end_with?('_transaction') + build_transaction( + id: raw_transaction['tx']['hash'], + created_at: build_ripple_time(raw_transaction['tx']['date']), + blockchain: blockchain, + source: raw_transaction + ) + end - raw_transaction = transactions_data.find { |transaction| match_generic_transaction?(transaction) } - return unless raw_transaction + def match_eos_transaction + raw_transaction = transactions.find { |transaction| match_eos_transaction?(transaction) } + build_transaction(id: raw_transaction['trx_id'], created_at: datetime_string_in_utc(raw_transaction['block_time']), blockchain: blockchain, source: raw_transaction) if raw_transaction + end - build_transaction( - id: raw_transaction['transaction_hash'], - created_at: datetime_string_in_utc(raw_transaction['time']), - blockchain: blockchain, - source: raw_transaction.merge(input: most_similar_input_by(output: raw_transaction)) - ) - end + def method_missing(method_name) + super unless method_name.start_with?('match_') && method_name.end_with?('_transaction') - def match_cardano_transaction?(transaction) - transaction_created_at = timestamp_in_utc(transaction['ctbTimeIssued']) + raw_transaction = transactions_data.find { |transaction| match_generic_transaction?(transaction) } + return unless raw_transaction - invoice_created_at.utc < transaction_created_at && transaction['ctbOutputs'].any?(&method(:match_by_output?)) - end + build_transaction( + id: raw_transaction['transaction_hash'], + created_at: datetime_string_in_utc(raw_transaction['time']), + blockchain: blockchain, + source: raw_transaction.merge(input: most_similar_input_by(output: raw_transaction)) + ) + end - def match_stellar_transaction?(transaction) - amount = transaction['amount'] - transaction_created_at = datetime_string_in_utc(transaction['created_at']) + def match_cardano_transaction?(transaction) + transaction_created_at = timestamp_in_utc(transaction['ctbTimeIssued']) - invoice_created_at.utc < transaction_created_at && match_amount?(amount) - end + invoice_created_at.utc < transaction_created_at && transaction['ctbOutputs'].any?(&method(:match_by_output?)) + end - def match_generic_transaction?(transaction) - amount = transaction['value'].to_f / amount_divider - transaction_created_at = datetime_string_in_utc(transaction['time']) + def match_stellar_transaction?(transaction) + amount = transaction['amount'] + transaction_created_at = datetime_string_in_utc(transaction['created_at']) - invoice_created_at.utc < transaction_created_at && match_amount?(amount) - end + invoice_created_at.utc < transaction_created_at && match_amount?(amount) + end - def match_ripple_transaction?(transaction) - transaction_info = transaction['tx'] - amount = transaction_info['Amount'].to_f / amount_divider - transaction_created_at = build_ripple_time(transaction_info['date']) + def match_generic_transaction?(transaction) + amount = transaction['value'].to_f / amount_divider + transaction_created_at = datetime_string_in_utc(transaction['time']) - invoice_created_at.utc < transaction_created_at && match_amount?(amount) && match_tag?(transaction_info['DestinationTag']) - end + invoice_created_at.utc < transaction_created_at && match_amount?(amount) + end - def match_tag?(tag) - invoice_memo.present? ? invoice_memo == tag.to_s : true - end + def match_ripple_transaction?(transaction) + transaction_info = transaction['tx'] + amount = transaction_info['Amount'].to_f / amount_divider + transaction_created_at = build_ripple_time(transaction_info['date']) - def match_eos_transaction?(transaction) - transaction_created_at = datetime_string_in_utc(transaction['block_time']) - amount_data = transaction['action_trace']['act']['data'] - invoice_created_at.utc < transaction_created_at && match_eos_amount?(amount_data) - end + invoice_created_at.utc < transaction_created_at && match_amount?(amount) && match_tag?(transaction_info['DestinationTag']) + end - def match_eos_amount?(amount_data) - amount, currency = amount_data['quantity'].split - match_amount?(amount) && currency == 'EOS' && match_tag?(amount_data['memo']) - end + def match_tag?(tag) + invoice_memo.present? ? invoice_memo == tag.to_s : true + end - def match_by_output?(output) - amount = output['ctaAmount']['getCoin'].to_f / amount_divider - match_amount?(amount) && output['ctaAddress'] == invoice.address - end + def match_eos_transaction?(transaction) + transaction_created_at = datetime_string_in_utc(transaction['block_time']) + amount_data = transaction['action_trace']['act']['data'] + invoice_created_at.utc < transaction_created_at && match_eos_amount?(amount_data) + end - def match_amount?(received_amount) - received_amount.to_d == invoice.amount.to_d - end + def match_eos_amount?(amount_data) + amount, currency = amount_data['quantity'].split + match_amount?(amount) && currency == 'EOS' && match_tag?(amount_data['memo']) + end - def datetime_string_in_utc(datetime_string) - DateTime.parse(datetime_string).utc - end + def match_by_output?(output) + amount = output['ctaAmount']['getCoin'].to_f / amount_divider + match_amount?(amount) && output['ctaAddress'] == invoice.address + end - def timestamp_in_utc(timestamp) - Time.at(timestamp).to_datetime.utc - end + def match_amount?(received_amount) + received_amount.to_d == invoice.amount.to_d + end - def build_ripple_time(timestamp) - timestamp_in_utc(timestamp + RIPPLE_AFTER_UNIX_EPOCH) - end + def datetime_string_in_utc(datetime_string) + DateTime.parse(datetime_string).utc + end - def transactions_data(direction: 'outputs') - signals = [] + def timestamp_in_utc(timestamp) + Time.at(timestamp).to_datetime.utc + end - transactions.each do |_transaction_id, transaction| - signals << transaction[direction] + def build_ripple_time(timestamp) + timestamp_in_utc(timestamp + RIPPLE_AFTER_UNIX_EPOCH) end - signals.flatten - end + def transactions_data(direction: 'outputs') + signals = [] - def most_similar_input_by(output:) - inputs = transactions_data(direction: 'inputs').select { |input| input['spending_time'] == output['time'] } - inputs.min_by { |input| (input['value'] - output['value']).abs } - end + transactions.each do |_transaction_id, transaction| + signals << transaction[direction] + end + + signals.flatten + end - def most_similar_cardano_input_by(output:, inputs:) - inputs.min_by { |input| (input['ctaAmount']['getCoin'].to_f - output['ctaAmount']['getCoin'].to_f).abs } + def most_similar_input_by(output:) + inputs = transactions_data(direction: 'inputs').select { |input| input['spending_time'] == output['time'] } + inputs.min_by { |input| (input['value'] - output['value']).abs } + end + + def most_similar_cardano_input_by(output:, inputs:) + inputs.min_by { |input| (input['ctaAmount']['getCoin'].to_f - output['ctaAmount']['getCoin'].to_f).abs } + end end end end diff --git a/lib/payment_services/bovapay/client.rb b/lib/payment_services/bovapay/client.rb index ce411baf..ba627993 100644 --- a/lib/payment_services/bovapay/client.rb +++ b/lib/payment_services/bovapay/client.rb @@ -1,63 +1,66 @@ # frozen_string_literal: true -class PaymentServices::Bovapay - class Client < ::PaymentServices::Base::Client - API_URL = 'https://bovatech.cc/v1' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Bovapay + class Client < ::PaymentServices::Base::Client + API_URL = 'https://bovatech.cc/v1' - def create_invoice(params:) - params.merge!(user_uuid: api_key) - safely_parse http_request( - url: "#{API_URL}/p2p_transactions", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def invoice(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/p2p_transactions/#{deposit_id}", - method: :GET, - headers: {} - ) - end + def create_invoice(params:) + params.merge!(user_uuid: api_key) + safely_parse http_request( + url: "#{API_URL}/p2p_transactions", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def create_payout(params:) - params.merge!(user_uuid: api_key) - safely_parse http_request( - url: "#{API_URL}/mass_transactions", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def invoice(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/p2p_transactions/#{deposit_id}", + method: :GET, + headers: {} + ) + end - def payout(withdrawal_id:) - safely_parse http_request( - url: "#{API_URL}/mass_transactions/#{withdrawal_id}", - method: :GET, - headers: {} - ) - end + def create_payout(params:) + params.merge!(user_uuid: api_key) + safely_parse http_request( + url: "#{API_URL}/mass_transactions", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - private + def payout(withdrawal_id:) + safely_parse http_request( + url: "#{API_URL}/mass_transactions/#{withdrawal_id}", + method: :GET, + headers: {} + ) + end - attr_reader :api_key, :secret_key + private - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'Signature' => signature - } - end + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'Signature' => signature + } + end - def build_signature(params) - Digest::SHA1.hexdigest("#{secret_key}#{params.to_json}") + def build_signature(params) + Digest::SHA1.hexdigest("#{secret_key}#{params.to_json}") + end end end end diff --git a/lib/payment_services/bovapay/invoice.rb b/lib/payment_services/bovapay/invoice.rb index cbe61a2b..720000f4 100644 --- a/lib/payment_services/bovapay/invoice.rb +++ b/lib/payment_services/bovapay/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Bovapay - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'successed' - FAILED_PROVIDER_STATE = 'failed' - self.table_name = 'bovapay_invoices' +module PaymentServices + class Bovapay + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'successed' + FAILED_PROVIDER_STATE = 'failed' - monetize :amount_cents, as: :amount + self.table_name = 'bovapay_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/bovapay/invoicer.rb b/lib/payment_services/bovapay/invoicer.rb index d0b77dc6..5e7f422c 100644 --- a/lib/payment_services/bovapay/invoicer.rb +++ b/lib/payment_services/bovapay/invoicer.rb @@ -3,73 +3,76 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Bovapay - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - PAYEER_TYPE = 'ftd' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise Error, "Can't create invoice: #{response['errors']}" if response['errors'].present? +module PaymentServices + class Bovapay + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + PAYEER_TYPE = 'ftd' - invoice.update!(deposit_id: response.dig('payload', 'id')) - card = response.dig('payload', 'resipient_card') - PaymentServices::Base::Wallet.new( - address: card['number'], - name: card['card_holder'], - memo: card['bank_full_name'] - ) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise Error, "Can't create invoice: #{response['errors']}" if response['errors'].present? - def create_invoice(money) - invoice - end + invoice.update!(deposit_id: response.dig('payload', 'id')) + card = response.dig('payload', 'resipient_card') + PaymentServices::Base::Wallet.new( + address: card['number'], + name: card['card_holder'], + memo: card['bank_full_name'] + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.invoice(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction.dig('payload', 'state')) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.invoice(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction.dig('payload', 'state')) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :card_bank, to: :bank_resolver + private - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + delegate :card_bank, to: :bank_resolver - def invoice_params - { - amount: invoice.amount.to_i, - merchant_id: order.public_id.to_s, - payeer_identifier: "#{Rails.env}_user_id_#{order.user_id}", - payeer_ip: order.remote_ip, - payeer_card_number: order.income_account, - payeer_type: PAYEER_TYPE, - lifetime: order.income_payment_timeout.to_i, - redirect_url: order.success_redirect, - callback_url: "#{routes_helper.public_public_callbacks_api_root_url}/v1/appex_money/confirm_payout", - payment_method: 'card', - currency: invoice.amount_currency.to_s.downcase, - bank_name: card_bank, - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def invoice_params + { + amount: invoice.amount.to_i, + merchant_id: order.public_id.to_s, + payeer_identifier: "#{Rails.env}_user_id_#{order.user_id}", + payeer_ip: order.remote_ip, + payeer_card_number: order.income_account, + payeer_type: PAYEER_TYPE, + lifetime: order.income_payment_timeout.to_i, + redirect_url: order.success_redirect, + callback_url: "#{routes_helper.public_public_callbacks_api_root_url}/v1/appex_money/confirm_payout", + payment_method: 'card', + currency: invoice.amount_currency.to_s.downcase, + bank_name: card_bank, + } + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/bovapay/payout.rb b/lib/payment_services/bovapay/payout.rb index e6dd0221..82da265a 100644 --- a/lib/payment_services/bovapay/payout.rb +++ b/lib/payment_services/bovapay/payout.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Bovapay - class Payout < ::PaymentServices::Base::FiatPayout - SUCCESS_PROVIDER_STATE = 'paid' - FAILED_PROVIDER_STATE = 'failed' - self.table_name = 'bovapay_payouts' +module PaymentServices + class Bovapay + class Payout < ::PaymentServices::Base::FiatPayout + SUCCESS_PROVIDER_STATE = 'paid' + FAILED_PROVIDER_STATE = 'failed' - monetize :amount_cents, as: :amount + self.table_name = 'bovapay_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/bovapay/payout_adapter.rb b/lib/payment_services/bovapay/payout_adapter.rb index 54d74b4c..556e53aa 100644 --- a/lib/payment_services/bovapay/payout_adapter.rb +++ b/lib/payment_services/bovapay/payout_adapter.rb @@ -3,62 +3,65 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Bovapay - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - Error = Class.new StandardError - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end +module PaymentServices + class Bovapay + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + Error = Class.new StandardError - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - transaction = client.payout(withdrawal_id: payout.withdrawal_id) - payout.update_state_by_provider(transaction.dig('payload', 'state')) - transaction - end + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - private + transaction = client.payout(withdrawal_id: payout.withdrawal_id) + payout.update_state_by_provider(transaction.dig('payload', 'state')) + transaction + end - delegate :sbp_bank, :sbp?, to: :bank_resolver + private - attr_reader :payout + delegate :sbp_bank, :sbp?, to: :bank_resolver - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise Error, "Can't create invoice: #{response['errors']}" if response['errors'].present? + attr_reader :payout - payout.pay!(withdrawal_id: response.dig('payload', 'id')) - end + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise Error, "Can't create invoice: #{response['errors']}" if response['errors'].present? - def payout_params - order = OrderPayout.find(payout.order_payout_id).order - params = { - to_card: payout.destination_account, - amount: payout.amount.to_i, - callback_url: "#{Rails.application.routes.url_helpers.public_public_callbacks_api_root_url}/v1/appex_money/confirm_payout", - merchant_id: "#{order.public_id}-#{payout.order_payout_id}", - currency: payout.amount_currency.to_s.downcase, - payment_method: sbp? ? 'sbp' : 'card', - lifetime: 3600 - } - params[:sbp_bank_name] = sbp_bank if sbp? - params - end + payout.pay!(withdrawal_id: response.dig('payload', 'id')) + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def payout_params + order = OrderPayout.find(payout.order_payout_id).order + params = { + to_card: payout.destination_account, + amount: payout.amount.to_i, + callback_url: "#{Rails.application.routes.url_helpers.public_public_callbacks_api_root_url}/v1/appex_money/confirm_payout", + merchant_id: "#{order.public_id}-#{payout.order_payout_id}", + currency: payout.amount_currency.to_s.downcase, + payment_method: sbp? ? 'sbp' : 'card', + lifetime: 3600 + } + params[:sbp_bank_name] = sbp_bank if sbp? + params + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/bridgex/client.rb b/lib/payment_services/bridgex/client.rb index 1ae4ff1c..82f9fce2 100644 --- a/lib/payment_services/bridgex/client.rb +++ b/lib/payment_services/bridgex/client.rb @@ -1,47 +1,50 @@ # frozen_string_literal: true -class PaymentServices::Bridgex - class Client < ::PaymentServices::Base::Client - API_URL = 'https://p2p-api.bridgex.ai/v1' - TEST_MODE = 'no' - - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - params.merge!(project: api_key, test_mode: TEST_MODE) - safely_parse http_request( - url: "#{API_URL}/payment/create", - method: :POST, - body: params.merge(sign: build_signature(params)).to_json, - headers: build_headers - ) - end - - def transaction(deposit_id:) - params = { project: api_key, order_id: deposit_id, test_mode: TEST_MODE } - safely_parse http_request( - url: "#{API_URL}/payment/status", - method: :POST, - body: params.merge(sign: build_signature(params)).to_json, - headers: build_headers - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_signature(params) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, params.to_json) - end - def build_headers - { - 'Content-Type' => 'application/json' - } +module PaymentServices + class Bridgex + class Client < ::PaymentServices::Base::Client + API_URL = 'https://p2p-api.bridgex.ai/v1' + TEST_MODE = 'no' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + params.merge!(project: api_key, test_mode: TEST_MODE) + safely_parse http_request( + url: "#{API_URL}/payment/create", + method: :POST, + body: params.merge(sign: build_signature(params)).to_json, + headers: build_headers + ) + end + + def transaction(deposit_id:) + params = { project: api_key, order_id: deposit_id, test_mode: TEST_MODE } + safely_parse http_request( + url: "#{API_URL}/payment/status", + method: :POST, + body: params.merge(sign: build_signature(params)).to_json, + headers: build_headers + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_signature(params) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, params.to_json) + end + + def build_headers + { + 'Content-Type' => 'application/json' + } + end end end end diff --git a/lib/payment_services/bridgex/invoice.rb b/lib/payment_services/bridgex/invoice.rb index d58598a0..d6a503c2 100644 --- a/lib/payment_services/bridgex/invoice.rb +++ b/lib/payment_services/bridgex/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Bridgex - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'paid' - FAILED_PROVIDER_STATE = 'cancel' - self.table_name = 'bridgex_invoices' +module PaymentServices + class Bridgex + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'paid' + FAILED_PROVIDER_STATE = 'cancel' - monetize :amount_cents, as: :amount + self.table_name = 'bridgex_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/bridgex/invoicer.rb b/lib/payment_services/bridgex/invoicer.rb index 264b4499..3e931591 100644 --- a/lib/payment_services/bridgex/invoicer.rb +++ b/lib/payment_services/bridgex/invoicer.rb @@ -3,78 +3,81 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Bridgex - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - PAYMENT_TIMEOUT_IN_SECONDS = 1800 - UNUSED_BANK_PARAM = 'unused_param' - - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) - - raise Error, "Can't create invoice: #{response}" if response['message'] - - invoice.update!( - deposit_id: order.public_id.to_s, - pay_url: response.dig('result', 'url') - ) - end - - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end - - def async_invoice_state_updater? - true - end - - def update_invoice_state! - transaction = client.transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction.dig('result', 'payment_status')) - end - - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end - - private - - delegate :card_bank, :sbp_bank, :sbp?, to: :resolver - delegate :require_income_card_verification, to: :income_payment_system - delegate :income_unk, :income_payment_system, to: :order - - def invoice_params - params = { - amount: invoice.amount.to_i, - order: order.public_id.to_s, - customer_ip: order.remote_ip, - customer_ident: '1', - card: card_payment?, - sbp: sbp_payment?, - qr: 'no', - ttl: PAYMENT_TIMEOUT_IN_SECONDS - } - params[:category] = 17 if !require_income_card_verification - params[:bank] = card_bank if !sbp? && card_bank != UNUSED_BANK_PARAM - params[:bank] = sbp_bank if sbp? && sbp_bank.present? - params - end - - def resolver - @resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end - - def sbp_payment? - sbp? ? 'yes' : 'no' - end - - def card_payment? - sbp? ? 'no' : 'yes' - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class Bridgex + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + PAYMENT_TIMEOUT_IN_SECONDS = 1800 + UNUSED_BANK_PARAM = 'unused_param' + + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) + + raise Error, "Can't create invoice: #{response}" if response['message'] + + invoice.update!( + deposit_id: order.public_id.to_s, + pay_url: response.dig('result', 'url') + ) + end + + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end + + def async_invoice_state_updater? + true + end + + def update_invoice_state! + transaction = client.transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction.dig('result', 'payment_status')) + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + private + + delegate :card_bank, :sbp_bank, :sbp?, to: :resolver + delegate :require_income_card_verification, to: :income_payment_system + delegate :income_unk, :income_payment_system, to: :order + + def invoice_params + params = { + amount: invoice.amount.to_i, + order: order.public_id.to_s, + customer_ip: order.remote_ip, + customer_ident: '1', + card: card_payment?, + sbp: sbp_payment?, + qr: 'no', + ttl: PAYMENT_TIMEOUT_IN_SECONDS + } + params[:category] = 17 if !require_income_card_verification + params[:bank] = card_bank if !sbp? && card_bank != UNUSED_BANK_PARAM + params[:bank] = sbp_bank if sbp? && sbp_bank.present? + params + end + + def resolver + @resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end + + def sbp_payment? + sbp? ? 'yes' : 'no' + end + + def card_payment? + sbp? ? 'no' : 'yes' + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/coin_payments_hub/client.rb b/lib/payment_services/coin_payments_hub/client.rb index f41d58e6..341a4150 100644 --- a/lib/payment_services/coin_payments_hub/client.rb +++ b/lib/payment_services/coin_payments_hub/client.rb @@ -4,60 +4,63 @@ require 'digest' require 'base64' -class PaymentServices::CoinPaymentsHub - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.coinpaymentshub.com/v1' - PROJECT_UUID = '039e74d1-ef06-483d-b64d-1fa56334aa65' - def initialize(api_key:) - @api_key = api_key - end +module PaymentServices + class CoinPaymentsHub + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.coinpaymentshub.com/v1' + PROJECT_UUID = '039e74d1-ef06-483d-b64d-1fa56334aa65' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/invoice/create", - method: :POST, - body: sign_params(params), - headers: build_headers - ) - end + def initialize(api_key:) + @api_key = api_key + end - def transaction(deposit_id:) - params = { order_id: deposit_id } - safely_parse http_request( - url: "#{API_URL}/invoice/status", - method: :POST, - body: sign_params(params), - headers: build_headers - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/invoice/create", + method: :POST, + body: sign_params(params), + headers: build_headers + ) + end - private + def transaction(deposit_id:) + params = { order_id: deposit_id } + safely_parse http_request( + url: "#{API_URL}/invoice/status", + method: :POST, + body: sign_params(params), + headers: build_headers + ) + end - attr_reader :api_key + private - def build_headers - { - 'Content-Type' => 'application/json', - 'project' => PROJECT_UUID - } - end + attr_reader :api_key + + def build_headers + { + 'Content-Type' => 'application/json', + 'project' => PROJECT_UUID + } + end + + def sign_params(params) + md5_api_key = Digest::MD5.hexdigest(api_key) + cipher = OpenSSL::Cipher.new("aes-256-cbc") + cipher.encrypt + iv = cipher.iv = cipher.random_iv + cipher.key = md5_api_key + + value = cipher.update(params.to_json) + cipher.final + value = Base64.encode64(value).chomp + iv = Base64.encode64(iv).chomp + mac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), md5_api_key, iv + value) + tag = '' - def sign_params(params) - md5_api_key = Digest::MD5.hexdigest(api_key) - cipher = OpenSSL::Cipher.new("aes-256-cbc") - cipher.encrypt - iv = cipher.iv = cipher.random_iv - cipher.key = md5_api_key - - value = cipher.update(params.to_json) + cipher.final - value = Base64.encode64(value).chomp - iv = Base64.encode64(iv).chomp - mac = OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), md5_api_key, iv + value) - tag = '' - - json_string = { iv: iv, value: value, mac: mac, tag: tag }.to_json - Base64.encode64(json_string).gsub(/\n/, '') + json_string = { iv: iv, value: value, mac: mac, tag: tag }.to_json + Base64.encode64(json_string).gsub(/\n/, '') + end end end end diff --git a/lib/payment_services/coin_payments_hub/currency_repository.rb b/lib/payment_services/coin_payments_hub/currency_repository.rb index 06dd3e40..8fe0a9a3 100644 --- a/lib/payment_services/coin_payments_hub/currency_repository.rb +++ b/lib/payment_services/coin_payments_hub/currency_repository.rb @@ -1,37 +1,40 @@ # frozen_string_literal: true -class PaymentServices::CoinPaymentsHub - class CurrencyRepository - TOKEN_NETWORK_TO_PROVIDER_TOKEN_ID = { - erc20: 'd08addf2-8af2-4bc0-9a4e-880fced2f0a0', - trc20: '2e0dc850-4b02-49a2-a1ae-6a3ea1daf344' - }.stringify_keys.freeze - TOKEN_NETWORK_TO_PROVIDER_NETWORK_ID = { - erc20: '808977fc-9a72-4725-b723-bde4c995dba4', - trc20: '51d1d35b-8d73-4384-aa7d-fad09de2c1dc' - }.stringify_keys.freeze - Error = Class.new StandardError - - include Virtus.model - - attribute :token_network, String - - def self.build_from(token_network:) - new(token_network: token_network) - end - def provider_token - TOKEN_NETWORK_TO_PROVIDER_TOKEN_ID[token_network] || raise_token_network_invalid! - end +module PaymentServices + class CoinPaymentsHub + class CurrencyRepository + TOKEN_NETWORK_TO_PROVIDER_TOKEN_ID = { + erc20: 'd08addf2-8af2-4bc0-9a4e-880fced2f0a0', + trc20: '2e0dc850-4b02-49a2-a1ae-6a3ea1daf344' + }.stringify_keys.freeze + TOKEN_NETWORK_TO_PROVIDER_NETWORK_ID = { + erc20: '808977fc-9a72-4725-b723-bde4c995dba4', + trc20: '51d1d35b-8d73-4384-aa7d-fad09de2c1dc' + }.stringify_keys.freeze + Error = Class.new StandardError - def provider_network - TOKEN_NETWORK_TO_PROVIDER_NETWORK_ID[token_network] || raise_token_network_invalid! - end + include Virtus.model + + attribute :token_network, String + + def self.build_from(token_network:) + new(token_network: token_network) + end + + def provider_token + TOKEN_NETWORK_TO_PROVIDER_TOKEN_ID[token_network] || raise_token_network_invalid! + end + + def provider_network + TOKEN_NETWORK_TO_PROVIDER_NETWORK_ID[token_network] || raise_token_network_invalid! + end - private + private - def raise_token_network_invalid! - raise Error, 'Token network invalid' + def raise_token_network_invalid! + raise Error, 'Token network invalid' + end end end end diff --git a/lib/payment_services/coin_payments_hub/invoice.rb b/lib/payment_services/coin_payments_hub/invoice.rb index ff559978..22b9d8ba 100644 --- a/lib/payment_services/coin_payments_hub/invoice.rb +++ b/lib/payment_services/coin_payments_hub/invoice.rb @@ -1,34 +1,37 @@ # frozen_string_literal: true -class PaymentServices::CoinPaymentsHub - class Invoice < ::PaymentServices::Base::CryptoInvoice - INITIAL_PROVIDER_STATE = 'wait' - Error = Class.new StandardError - self.table_name = 'coin_payments_hub_invoices' +module PaymentServices + class CoinPaymentsHub + class Invoice < ::PaymentServices::Base::CryptoInvoice + INITIAL_PROVIDER_STATE = 'wait' + Error = Class.new StandardError - monetize :amount_cents, as: :amount + self.table_name = 'coin_payments_hub_invoices' - def update_state_by_transaction!(transaction) - validate_transaction_amount!(transaction: transaction) + monetize :amount_cents, as: :amount - bind_transaction! if pending? - update!(provider_state: transaction.status) - pay!(payload: transaction) if transaction.succeed? - cancel! if transaction.failed? - end + def update_state_by_transaction!(transaction) + validate_transaction_amount!(transaction: transaction) - def transaction_created_at - nil - end + bind_transaction! if pending? + update!(provider_state: transaction.status) + pay!(payload: transaction) if transaction.succeed? + cancel! if transaction.failed? + end + + def transaction_created_at + nil + end - private + private - delegate :income_payment_system, to: :order - delegate :token_network, to: :income_payment_system + delegate :income_payment_system, to: :order + delegate :token_network, to: :income_payment_system - def validate_transaction_amount!(transaction:) - raise Error, "#{amount.to_f} #{amount_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_currency) + def validate_transaction_amount!(transaction:) + raise Error, "#{amount.to_f} #{amount_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_currency) + end end end end diff --git a/lib/payment_services/coin_payments_hub/invoicer.rb b/lib/payment_services/coin_payments_hub/invoicer.rb index a9a63008..238b64d8 100644 --- a/lib/payment_services/coin_payments_hub/invoicer.rb +++ b/lib/payment_services/coin_payments_hub/invoicer.rb @@ -5,69 +5,72 @@ require_relative 'transaction' require_relative 'currency_repository' -class PaymentServices::CoinPaymentsHub - class Invoicer < ::PaymentServices::Base::Invoicer - PROVIDER_SUCCESS_STATE = 'ok' - Error = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) - validate_response!(response) +module PaymentServices + class CoinPaymentsHub + class Invoicer < ::PaymentServices::Base::Invoicer + PROVIDER_SUCCESS_STATE = 'ok' + Error = Class.new StandardError - create_temp_kassa_wallet(address: response.dig('result', 'address')) - invoice.update!(deposit_id: order.public_id.to_s) - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) + validate_response!(response) - def async_invoice_state_updater? - true - end + create_temp_kassa_wallet(address: response.dig('result', 'address')) + invoice.update!(deposit_id: order.public_id.to_s) + end - def update_invoice_state! - response = client.transaction(deposit_id: invoice.deposit_id) - validate_response!(response) + def async_invoice_state_updater? + true + end - raw_transaction = response['result'] - transaction = Transaction.build_from(raw_transaction) - invoice.update_state_by_transaction!(transaction) - end + def update_invoice_state! + response = client.transaction(deposit_id: invoice.deposit_id) + validate_response!(response) - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + raw_transaction = response['result'] + transaction = Transaction.build_from(raw_transaction) + invoice.update_state_by_transaction!(transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :income_payment_system, to: :order - delegate :withdrawal_wallet, to: :income_payment_system - delegate :token_network, to: :income_payment_system - delegate :wallets, to: :income_payment_system + private - def invoice_params - { - amount: invoice.amount.to_f, - network: CurrencyRepository.build_from(token_network: token_network).provider_network, - token: CurrencyRepository.build_from(token_network: token_network).provider_token, - withdrawal_wallet: withdrawal_wallet, - order_id: order.public_id.to_s, - ttl: PreliminaryOrder::MAX_LIVE.to_i, - is_client_repeat_wallet: false - } - end + delegate :income_payment_system, to: :order + delegate :withdrawal_wallet, to: :income_payment_system + delegate :token_network, to: :income_payment_system + delegate :wallets, to: :income_payment_system - def create_temp_kassa_wallet(address:) - wallet = wallets.find_or_create_by(account: address) - order.update(income_wallet_id: wallet.id) - end + def invoice_params + { + amount: invoice.amount.to_f, + network: CurrencyRepository.build_from(token_network: token_network).provider_network, + token: CurrencyRepository.build_from(token_network: token_network).provider_token, + withdrawal_wallet: withdrawal_wallet, + order_id: order.public_id.to_s, + ttl: PreliminaryOrder::MAX_LIVE.to_i, + is_client_repeat_wallet: false + } + end - def validate_response!(response) - return if response['state'] == PROVIDER_SUCCESS_STATE + def create_temp_kassa_wallet(address:) + wallet = wallets.find_or_create_by(account: address) + order.update(income_wallet_id: wallet.id) + end + + def validate_response!(response) + return if response['state'] == PROVIDER_SUCCESS_STATE - raise Error, "Can't create invoice: #{response.dig('result', 'error')}" - end + raise Error, "Can't create invoice: #{response.dig('result', 'error')}" + end - def client - @client ||= Client.new(api_key: api_key) + def client + @client ||= Client.new(api_key: api_key) + end end end end diff --git a/lib/payment_services/coin_payments_hub/transaction.rb b/lib/payment_services/coin_payments_hub/transaction.rb index 5790155e..9c1c2fe2 100644 --- a/lib/payment_services/coin_payments_hub/transaction.rb +++ b/lib/payment_services/coin_payments_hub/transaction.rb @@ -1,40 +1,43 @@ # frozen_string_literal: true -class PaymentServices::CoinPaymentsHub - class Transaction - SUCCESS_PROVIDER_STATE = 'success' - FAILED_PROVIDER_STATE = 'cancel' - - include Virtus.model - - attribute :amount, Float - attribute :currency, String - attribute :status, String - attribute :source, Hash - - def self.build_from(raw_transaction) - new( - amount: raw_transaction['paid_amount'].to_f, - currency: raw_transaction['currency_symbol'], - status: raw_transaction['status'], - source: raw_transaction - ) - end - - def to_s - source.to_s - end - - def valid_amount?(payout_amount, payout_currency) - (amount.zero? || amount == payout_amount) && currency == payout_currency - end - - def succeed? - status == SUCCESS_PROVIDER_STATE - end - def failed? - status == FAILED_PROVIDER_STATE +module PaymentServices + class CoinPaymentsHub + class Transaction + SUCCESS_PROVIDER_STATE = 'success' + FAILED_PROVIDER_STATE = 'cancel' + + include Virtus.model + + attribute :amount, Float + attribute :currency, String + attribute :status, String + attribute :source, Hash + + def self.build_from(raw_transaction) + new( + amount: raw_transaction['paid_amount'].to_f, + currency: raw_transaction['currency_symbol'], + status: raw_transaction['status'], + source: raw_transaction + ) + end + + def to_s + source.to_s + end + + def valid_amount?(payout_amount, payout_currency) + (amount.zero? || amount == payout_amount) && currency == payout_currency + end + + def succeed? + status == SUCCESS_PROVIDER_STATE + end + + def failed? + status == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/crypto_apis/clients/base_client.rb b/lib/payment_services/crypto_apis/clients/base_client.rb index a0a70a0d..c6ee6183 100644 --- a/lib/payment_services/crypto_apis/clients/base_client.rb +++ b/lib/payment_services/crypto_apis/clients/base_client.rb @@ -2,87 +2,90 @@ # Copyright (c) 2020 FINFEX https://github.com/finfex -class PaymentServices::CryptoApis - module Clients - class BaseClient - include AutoLogger - TIMEOUT = 30 - API_URL = 'https://api.cryptoapis.io/v1' - NETWORK = 'mainnet' - def initialize(api_key:, currency:) - @api_key = api_key - @currency = currency - end +module PaymentServices + class CryptoApis + module Clients + class BaseClient + include AutoLogger + TIMEOUT = 30 + API_URL = 'https://api.cryptoapis.io/v1' + NETWORK = 'mainnet' - def address_transactions(address) - safely_parse http_request( - url: "#{base_url}/address/#{address}/basic/transactions?legacy=true", - method: :GET - ) - end + def initialize(api_key:, currency:) + @api_key = api_key + @currency = currency + end - def transaction_details(transaction_id) - safely_parse http_request( - url: "#{base_url}/txs/basic/txid/#{transaction_id}", - method: :GET - ) - end + def address_transactions(address) + safely_parse http_request( + url: "#{base_url}/address/#{address}/basic/transactions?legacy=true", + method: :GET + ) + end - private + def transaction_details(transaction_id) + safely_parse http_request( + url: "#{base_url}/txs/basic/txid/#{transaction_id}", + method: :GET + ) + end - attr_reader :api_key, :currency + private - def base_url - "#{API_URL}/bc/#{currency}/#{NETWORK}" - end + attr_reader :api_key, :currency - def http_request(url:, method:, body: nil) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + def base_url + "#{API_URL}/bc/#{currency}/#{NETWORK}" + end - def build_request(uri:, method:, body: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, headers) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + def http_request(url:, method:, body: nil) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def build_request(uri:, method:, body: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, headers) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - def headers - { - 'Content-Type': 'application/json', - 'Cache-Control': 'no-cache', - 'X-API-Key': api_key - } - end + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end + + def headers + { + 'Content-Type': 'application/json', + 'Cache-Control': 'no-cache', + 'X-API-Key': api_key + } + end - def safely_parse(response) - res = JSON.parse(response.body).with_indifferent_access - logger.info "Response: #{res}" - res - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + def safely_parse(response) + res = JSON.parse(response.body).with_indifferent_access + logger.info "Response: #{res}" + res + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/crypto_apis/clients/dash_client.rb b/lib/payment_services/crypto_apis/clients/dash_client.rb index 6de4e94d..be9fac80 100644 --- a/lib/payment_services/crypto_apis/clients/dash_client.rb +++ b/lib/payment_services/crypto_apis/clients/dash_client.rb @@ -2,13 +2,16 @@ require_relative 'base_client' -class PaymentServices::CryptoApis - module Clients - class DashClient < PaymentServices::CryptoApis::Clients::BaseClient - private - def base_url - "#{API_URL}/bc/dash/#{NETWORK}" +module PaymentServices + class CryptoApis + module Clients + class DashClient < PaymentServices::CryptoApis::Clients::BaseClient + private + + def base_url + "#{API_URL}/bc/dash/#{NETWORK}" + end end end end diff --git a/lib/payment_services/crypto_apis/clients/ethereum_client.rb b/lib/payment_services/crypto_apis/clients/ethereum_client.rb index 7775e0b5..21c875b4 100644 --- a/lib/payment_services/crypto_apis/clients/ethereum_client.rb +++ b/lib/payment_services/crypto_apis/clients/ethereum_client.rb @@ -2,14 +2,17 @@ require_relative 'base_client' -class PaymentServices::CryptoApis - module Clients - class EthereumClient < PaymentServices::CryptoApis::Clients::BaseClient - def transaction_details(transaction_id) - safely_parse http_request( - url: "#{base_url}/txs/basic/hash/#{transaction_id}", - method: :GET - ) + +module PaymentServices + class CryptoApis + module Clients + class EthereumClient < PaymentServices::CryptoApis::Clients::BaseClient + def transaction_details(transaction_id) + safely_parse http_request( + url: "#{base_url}/txs/basic/hash/#{transaction_id}", + method: :GET + ) + end end end end diff --git a/lib/payment_services/crypto_apis/clients/omni_client.rb b/lib/payment_services/crypto_apis/clients/omni_client.rb index 96091528..3017596f 100644 --- a/lib/payment_services/crypto_apis/clients/omni_client.rb +++ b/lib/payment_services/crypto_apis/clients/omni_client.rb @@ -2,13 +2,16 @@ require_relative 'base_client' -class PaymentServices::CryptoApis - module Clients - class OmniClient < PaymentServices::CryptoApis::Clients::BaseClient - private - def base_url - "#{API_URL}/bc/btc/#{currency}/#{NETWORK}" +module PaymentServices + class CryptoApis + module Clients + class OmniClient < PaymentServices::CryptoApis::Clients::BaseClient + private + + def base_url + "#{API_URL}/bc/btc/#{currency}/#{NETWORK}" + end end end end diff --git a/lib/payment_services/crypto_apis/invoice.rb b/lib/payment_services/crypto_apis/invoice.rb index 39357fe1..f79819f5 100644 --- a/lib/payment_services/crypto_apis/invoice.rb +++ b/lib/payment_services/crypto_apis/invoice.rb @@ -2,48 +2,51 @@ # Copyright (c) 2020 FINFEX https://github.com/finfex -class PaymentServices::CryptoApis - class Invoice < ApplicationRecord - CONFIRMATIONS_FOR_COMPLETE = 1 - include Workflow - self.table_name = 'crypto_apis_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class CryptoApis + class Invoice < ApplicationRecord + CONFIRMATIONS_FOR_COMPLETE = 1 + include Workflow + self.table_name = 'crypto_apis_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :has_transaction, transitions_to: :with_transaction - end - state :with_transaction do - on_entry do - order.make_reserve! + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :has_transaction, transitions_to: :with_transaction + end + state :with_transaction do + on_entry do + order.make_reserve! + end + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled end - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def complete_payment? - confirmations >= CONFIRMATIONS_FOR_COMPLETE - end + def complete_payment? + confirmations >= CONFIRMATIONS_FOR_COMPLETE + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end end end end diff --git a/lib/payment_services/crypto_apis/invoicer.rb b/lib/payment_services/crypto_apis/invoicer.rb index 6eef33e4..78a7faae 100644 --- a/lib/payment_services/crypto_apis/invoicer.rb +++ b/lib/payment_services/crypto_apis/invoicer.rb @@ -5,116 +5,119 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::CryptoApis - class Invoicer < ::PaymentServices::Base::Invoicer - TRANSACTION_TIME_THRESHOLD = 30.minutes - ETC_TIME_THRESHOLD = 20.seconds - PARTNERS_RECEIVED_AMOUNT_DELTA = 0.000001 - - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end - def update_invoice_state! - transaction = transaction_for(invoice) - return if transaction.nil? +module PaymentServices + class CryptoApis + class Invoicer < ::PaymentServices::Base::Invoicer + TRANSACTION_TIME_THRESHOLD = 30.minutes + ETC_TIME_THRESHOLD = 20.seconds + PARTNERS_RECEIVED_AMOUNT_DELTA = 0.000001 - invoice.has_transaction! if invoice.pending? + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - update_invoice_details(invoice: invoice, transaction: transaction) - invoice.pay!(payload: transaction) if invoice.complete_payment? - end + def update_invoice_state! + transaction = transaction_for(invoice) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.has_transaction! if invoice.pending? - def async_invoice_state_updater? - true - end + update_invoice_details(invoice: invoice, transaction: transaction) + invoice.pay!(payload: transaction) if invoice.complete_payment? + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def update_invoice_details(invoice:, transaction:) - invoice.transaction_created_at ||= Time.parse(transaction[:datetime]) - invoice.transaction_id ||= transaction[:txid] || transaction[:hash] - invoice.confirmations = transaction[:confirmations] - invoice.save! - end + def async_invoice_state_updater? + true + end - def transaction_for(invoice) - if invoice.transaction_id - client.transaction_details(invoice.transaction_id)[:payload] - else - response = client.address_transactions(invoice.address) - raise response[:meta][:error][:message] if response.dig(:meta, :error, :message) + private - response[:payload].find do |transaction| - match_transaction?(transaction) - end if response[:payload] + def update_invoice_details(invoice:, transaction:) + invoice.transaction_created_at ||= Time.parse(transaction[:datetime]) + invoice.transaction_id ||= transaction[:txid] || transaction[:hash] + invoice.confirmations = transaction[:confirmations] + invoice.save! end - end - def match_transaction?(transaction) - amount = parse_received_amount(transaction) - transaction_created_at = timestamp_in_utc(transaction[:timestamp]) - invoice_created_at = expected_invoice_created_at - return false if invoice_created_at >= transaction_created_at + def transaction_for(invoice) + if invoice.transaction_id + client.transaction_details(invoice.transaction_id)[:payload] + else + response = client.address_transactions(invoice.address) + raise response[:meta][:error][:message] if response.dig(:meta, :error, :message) + + response[:payload].find do |transaction| + match_transaction?(transaction) + end if response[:payload] + end + end - time_diff = (transaction_created_at - invoice_created_at) / 1.minute - match_by_amount_and_time?(amount, time_diff) || match_by_txid_amount_and_time?(amount, transaction[:txid], time_diff) - end + def match_transaction?(transaction) + amount = parse_received_amount(transaction) + transaction_created_at = timestamp_in_utc(transaction[:timestamp]) + invoice_created_at = expected_invoice_created_at + return false if invoice_created_at >= transaction_created_at - def match_by_amount_and_time?(amount, time_diff) - match_amount?(amount) && match_transaction_time_threshold?(time_diff) - end + time_diff = (transaction_created_at - invoice_created_at) / 1.minute + match_by_amount_and_time?(amount, time_diff) || match_by_txid_amount_and_time?(amount, transaction[:txid], time_diff) + end + + def match_by_amount_and_time?(amount, time_diff) + match_amount?(amount) && match_transaction_time_threshold?(time_diff) + end - def match_by_txid_amount_and_time?(amount, txid, time_diff) - invoice.possible_transaction_id.present? && - match_txid?(txid) && - match_amount_with_delta?(amount) && - match_transaction_time_threshold?(time_diff) - end + def match_by_txid_amount_and_time?(amount, txid, time_diff) + invoice.possible_transaction_id.present? && + match_txid?(txid) && + match_amount_with_delta?(amount) && + match_transaction_time_threshold?(time_diff) + end - def match_amount?(received_amount) - received_amount.to_d == invoice.amount.to_d - end + def match_amount?(received_amount) + received_amount.to_d == invoice.amount.to_d + end - def match_amount_with_delta?(received_amount) - amount_diff = received_amount.to_d - invoice.amount.to_d - amount_diff >= 0 && amount_diff <= PARTNERS_RECEIVED_AMOUNT_DELTA - end + def match_amount_with_delta?(received_amount) + amount_diff = received_amount.to_d - invoice.amount.to_d + amount_diff >= 0 && amount_diff <= PARTNERS_RECEIVED_AMOUNT_DELTA + end - def match_transaction_time_threshold?(time_diff) - time_diff.round.minutes < TRANSACTION_TIME_THRESHOLD - end + def match_transaction_time_threshold?(time_diff) + time_diff.round.minutes < TRANSACTION_TIME_THRESHOLD + end - def match_txid?(txid) - txid == invoice.possible_transaction_id - end + def match_txid?(txid) + txid == invoice.possible_transaction_id + end - def parse_received_amount(transaction) - received_amount = transaction[:amount] - received_amount = transaction[:received][invoice.address] unless transaction[:received][invoice.address] == invoice.address - received_amount - end + def parse_received_amount(transaction) + received_amount = transaction[:amount] + received_amount = transaction[:received][invoice.address] unless transaction[:received][invoice.address] == invoice.address + received_amount + end - def timestamp_in_utc(timestamp) - DateTime.strptime(timestamp.to_s,'%s').utc - end + def timestamp_in_utc(timestamp) + DateTime.strptime(timestamp.to_s,'%s').utc + end - def expected_invoice_created_at - invoice_created_at = invoice.created_at.utc - invoice_created_at -= ETC_TIME_THRESHOLD if invoice.amount_currency == 'ETC' - invoice_created_at - end + def expected_invoice_created_at + invoice_created_at = invoice.created_at.utc + invoice_created_at -= ETC_TIME_THRESHOLD if invoice.amount_currency == 'ETC' + invoice_created_at + end - def client - @client ||= begin - wallet = order.income_wallet - currency = wallet.currency.to_s.downcase + def client + @client ||= begin + wallet = order.income_wallet + currency = wallet.currency.to_s.downcase - Client.new(currency: currency).invoice.new(api_key: api_key, currency: currency) + Client.new(currency: currency).invoice.new(api_key: api_key, currency: currency) + end end end end diff --git a/lib/payment_services/crypto_apis/payout.rb b/lib/payment_services/crypto_apis/payout.rb index 6cfd44ec..97371767 100644 --- a/lib/payment_services/crypto_apis/payout.rb +++ b/lib/payment_services/crypto_apis/payout.rb @@ -1,40 +1,43 @@ # frozen_string_literal: true -class PaymentServices::CryptoApis - class Payout < ApplicationRecord - CONFIRMATIONS_FOR_COMPLETE = 1 - include Workflow - self.table_name = 'crypto_apis_payouts' - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :address, :fee, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed +module PaymentServices + class CryptoApis + class Payout < ApplicationRecord + CONFIRMATIONS_FOR_COMPLETE = 1 + include Workflow + self.table_name = 'crypto_apis_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :address, :fee, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(txid:) - update(txid: txid) - end + def pay(txid:) + update(txid: txid) + end - def success? - return false if confirmations.nil? + def success? + return false if confirmations.nil? - confirmations >= CONFIRMATIONS_FOR_COMPLETE - end + confirmations >= CONFIRMATIONS_FOR_COMPLETE + end - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end end end end diff --git a/lib/payment_services/crypto_apis/payout_adapter.rb b/lib/payment_services/crypto_apis/payout_adapter.rb index e348695c..6a6b0664 100644 --- a/lib/payment_services/crypto_apis/payout_adapter.rb +++ b/lib/payment_services/crypto_apis/payout_adapter.rb @@ -3,79 +3,82 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::CryptoApis - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - delegate :outcome_transaction_fee_amount, to: :payment_system - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - raise 'amount is not a Money' unless amount.is_a? Money - - make_payout( - amount: amount, - address: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? +module PaymentServices + class CryptoApis + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + delegate :outcome_transaction_fee_amount, to: :payment_system - response = client.transaction_details(payout.txid) + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + raise 'amount is not a Money' unless amount.is_a? Money - payout.update!( - confirmations: response[:payload][:confirmations], - fee: response[:payload][:fee].to_f - ) if response[:payload] - payout.confirm! if payout.success? + make_payout( + amount: amount, + address: destination_account, + order_payout_id: order_payout_id + ) + end - response[:payload] - end + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? - def payout - @payout ||= Payout.find_by(id: payout_id) - end + response = client.transaction_details(payout.txid) - private + payout.update!( + confirmations: response[:payload][:confirmations], + fee: response[:payload][:fee].to_f + ) if response[:payload] + payout.confirm! if payout.success? - attr_accessor :payout_id + response[:payload] + end - def make_payout(amount:, address:, order_payout_id:) - fee = outcome_transaction_fee_amount || provider_fee - raise "Fee is too low: #{fee}" if fee < 0.00000001 + def payout + @payout ||= Payout.find_by(id: payout_id) + end - @payout_id = create_payout!(amount: amount, address: address, fee: fee, order_payout_id: order_payout_id).id + private - response = client.make_payout(payout: payout, wallet_transfers: wallet_transfers) - raise "Can't process payout: #{response[:meta][:error][:message]}" if response.dig(:meta, :error, :message) + attr_accessor :payout_id - # NOTE: hex for: ETH/ETC. txid for: BTC/OMNI/BCH/LTC/DOGE/DASH - hash = response[:payload][:txid] || response[:payload][:hex] - raise "Didn't get transaction hash" unless hash + def make_payout(amount:, address:, order_payout_id:) + fee = outcome_transaction_fee_amount || provider_fee + raise "Fee is too low: #{fee}" if fee < 0.00000001 - payout.pay!(txid: hash) - end + @payout_id = create_payout!(amount: amount, address: address, fee: fee, order_payout_id: order_payout_id).id - def provider_fee - response = client.transactions_average_fee - raise "Can't get transaction fee: #{response[:meta][:error][:message]}" if response.dig(:meta, :error, :message) + response = client.make_payout(payout: payout, wallet_transfers: wallet_transfers) + raise "Can't process payout: #{response[:meta][:error][:message]}" if response.dig(:meta, :error, :message) - payload = response[:payload] - fee = payload[:standard].to_f - fee = payload[:average].to_f if fee == 0.0 - fee - end + # NOTE: hex for: ETH/ETC. txid for: BTC/OMNI/BCH/LTC/DOGE/DASH + hash = response[:payload][:txid] || response[:payload][:hex] + raise "Didn't get transaction hash" unless hash - def client - @client ||= begin - currency = wallet.currency.to_s.downcase + payout.pay!(txid: hash) + end + + def provider_fee + response = client.transactions_average_fee + raise "Can't get transaction fee: #{response[:meta][:error][:message]}" if response.dig(:meta, :error, :message) - Client.new(currency: currency).payout.new(api_key: api_key, currency: currency) + payload = response[:payload] + fee = payload[:standard].to_f + fee = payload[:average].to_f if fee == 0.0 + fee end - end - def create_payout!(amount:, address:, fee:, order_payout_id:) - Payout.create!(amount: amount, address: address, fee: fee, order_payout_id: order_payout_id) + def client + @client ||= begin + currency = wallet.currency.to_s.downcase + + Client.new(currency: currency).payout.new(api_key: api_key, currency: currency) + end + end + + def create_payout!(amount:, address:, fee:, order_payout_id:) + Payout.create!(amount: amount, address: address, fee: fee, order_payout_id: order_payout_id) + end end end end diff --git a/lib/payment_services/crypto_apis/payout_clients/base_client.rb b/lib/payment_services/crypto_apis/payout_clients/base_client.rb index 577441da..86e9dbbf 100644 --- a/lib/payment_services/crypto_apis/payout_clients/base_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/base_client.rb @@ -2,52 +2,55 @@ require_relative '../clients/base_client' -class PaymentServices::CryptoApis - module PayoutClients - class BaseClient < PaymentServices::CryptoApis::Clients::BaseClient - DEFAULT_PARAMS = { replaceable: true } - - def make_payout(payout:, wallet_transfers:) - safely_parse http_request( - url: "#{base_url}/txs/new", - method: :POST, - body: api_query_for(payout, wallet_transfers) - ) - end - - def transactions_average_fee - safely_parse(http_request( - url: "#{base_url}/txs/fee", - method: :GET - )) - end - - private - - def api_query_for(payout, wallet_transfers) - { - createTx: { - inputs: inputs(wallet_transfers), - outputs: [{ address: payout.address, value: payout.amount.to_d }], - fee: { value: payout.fee }.merge(pay_fee_from_address(payout)) - }, - wifs: wifs(wallet_transfers) - }.merge(DEFAULT_PARAMS) - end - - def inputs(wallet_transfers) - wallet_transfers.map { |wallet_transfer| { 'address' => wallet_transfer.wallet.account, 'value' => wallet_transfer.amount.to_f } } - end - - def wifs(wallet_transfers) - wallet_transfers.map { |wallet_transfer| wallet_transfer.wallet.outcome_api_secret } - end - - def pay_fee_from_address(payout) - wallet_for_fee = payout.order_payout.wallet_for_fee - return {} if wallet_for_fee.nil? - { address: wallet_for_fee.account } +module PaymentServices + class CryptoApis + module PayoutClients + class BaseClient < PaymentServices::CryptoApis::Clients::BaseClient + DEFAULT_PARAMS = { replaceable: true } + + def make_payout(payout:, wallet_transfers:) + safely_parse http_request( + url: "#{base_url}/txs/new", + method: :POST, + body: api_query_for(payout, wallet_transfers) + ) + end + + def transactions_average_fee + safely_parse(http_request( + url: "#{base_url}/txs/fee", + method: :GET + )) + end + + private + + def api_query_for(payout, wallet_transfers) + { + createTx: { + inputs: inputs(wallet_transfers), + outputs: [{ address: payout.address, value: payout.amount.to_d }], + fee: { value: payout.fee }.merge(pay_fee_from_address(payout)) + }, + wifs: wifs(wallet_transfers) + }.merge(DEFAULT_PARAMS) + end + + def inputs(wallet_transfers) + wallet_transfers.map { |wallet_transfer| { 'address' => wallet_transfer.wallet.account, 'value' => wallet_transfer.amount.to_f } } + end + + def wifs(wallet_transfers) + wallet_transfers.map { |wallet_transfer| wallet_transfer.wallet.outcome_api_secret } + end + + def pay_fee_from_address(payout) + wallet_for_fee = payout.order_payout.wallet_for_fee + return {} if wallet_for_fee.nil? + + { address: wallet_for_fee.account } + end end end end diff --git a/lib/payment_services/crypto_apis/payout_clients/dash_client.rb b/lib/payment_services/crypto_apis/payout_clients/dash_client.rb index e29bce6f..c62a89f9 100644 --- a/lib/payment_services/crypto_apis/payout_clients/dash_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/dash_client.rb @@ -2,23 +2,26 @@ require_relative 'base_client' -class PaymentServices::CryptoApis - module PayoutClients - class DashClient < PaymentServices::CryptoApis::PayoutClients::BaseClient - DEPRECATED_OPTION = { deprecated_rpc: 'sign_raw_transaction' } - def make_payout(payout:, wallet_transfers:) - safely_parse http_request( - url: "#{base_url}/txs/new", - method: :POST, - body: api_query_for(payout, wallet_transfers).merge(DEPRECATED_OPTION) - ) - end +module PaymentServices + class CryptoApis + module PayoutClients + class DashClient < PaymentServices::CryptoApis::PayoutClients::BaseClient + DEPRECATED_OPTION = { deprecated_rpc: 'sign_raw_transaction' } + + def make_payout(payout:, wallet_transfers:) + safely_parse http_request( + url: "#{base_url}/txs/new", + method: :POST, + body: api_query_for(payout, wallet_transfers).merge(DEPRECATED_OPTION) + ) + end - private + private - def base_url - "#{API_URL}/bc/dash/#{NETWORK}" + def base_url + "#{API_URL}/bc/dash/#{NETWORK}" + end end end end diff --git a/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb b/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb index fbd06260..b082e50d 100644 --- a/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb @@ -2,37 +2,40 @@ require_relative '../clients/ethereum_client' -class PaymentServices::CryptoApis - module PayoutClients - class EthereumClient < PaymentServices::CryptoApis::Clients::EthereumClient - GAS_LIMIT = 100_000 - def make_payout(payout:, wallet_transfers:) - safely_parse http_request( - url: "#{base_url}/txs/new-pvtkey", - method: :POST, - body: api_query_for(payout, wallet_transfers.first.wallet) - ) - end +module PaymentServices + class CryptoApis + module PayoutClients + class EthereumClient < PaymentServices::CryptoApis::Clients::EthereumClient + GAS_LIMIT = 100_000 - def transactions_average_fee - safely_parse(http_request( - url: "#{base_url}/txs/fee", - method: :GET - )) - end + def make_payout(payout:, wallet_transfers:) + safely_parse http_request( + url: "#{base_url}/txs/new-pvtkey", + method: :POST, + body: api_query_for(payout, wallet_transfers.first.wallet) + ) + end + + def transactions_average_fee + safely_parse(http_request( + url: "#{base_url}/txs/fee", + method: :GET + )) + end - private + private - def api_query_for(payout, wallet) - { - fromAddress: wallet.account, - toAddress: payout.address, - value: payout.amount.to_d, - gasPrice: payout.fee.to_i, - gasLimit: GAS_LIMIT, - privateKey: wallet.outcome_api_secret - } + def api_query_for(payout, wallet) + { + fromAddress: wallet.account, + toAddress: payout.address, + value: payout.amount.to_d, + gasPrice: payout.fee.to_i, + gasLimit: GAS_LIMIT, + privateKey: wallet.outcome_api_secret + } + end end end end diff --git a/lib/payment_services/crypto_apis/payout_clients/omni_client.rb b/lib/payment_services/crypto_apis/payout_clients/omni_client.rb index 3d0719c5..579968d3 100644 --- a/lib/payment_services/crypto_apis/payout_clients/omni_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/omni_client.rb @@ -2,37 +2,40 @@ require_relative '../clients/omni_client' -class PaymentServices::CryptoApis - module PayoutClients - class OmniClient < PaymentServices::CryptoApis::Clients::OmniClient - TOKEN_PROPERTY_ID = 2 - def make_payout(payout:, wallet:) - safely_parse http_request( - url: "#{base_url}/txs/new", - method: :POST, - body: api_query_for(payout, wallet) - ) - end +module PaymentServices + class CryptoApis + module PayoutClients + class OmniClient < PaymentServices::CryptoApis::Clients::OmniClient + TOKEN_PROPERTY_ID = 2 - def transactions_average_fee - safely_parse(http_request( - url: "#{base_url}/txs/fee", - method: :GET - )) - end + def make_payout(payout:, wallet:) + safely_parse http_request( + url: "#{base_url}/txs/new", + method: :POST, + body: api_query_for(payout, wallet) + ) + end + + def transactions_average_fee + safely_parse(http_request( + url: "#{base_url}/txs/fee", + method: :GET + )) + end - private + private - def api_query_for(payout, wallet) - { - from: wallet.account, - to: payout.address, - value: payout.amount.to_d, - fee: payout.fee, - propertyID: TOKEN_PROPERTY_ID, - wif: wallet.outcome_api_secret - } + def api_query_for(payout, wallet) + { + from: wallet.account, + to: payout.address, + value: payout.amount.to_d, + fee: payout.fee, + propertyID: TOKEN_PROPERTY_ID, + wif: wallet.outcome_api_secret + } + end end end end diff --git a/lib/payment_services/crypto_apis_v2/blockchain.rb b/lib/payment_services/crypto_apis_v2/blockchain.rb index 42d78172..1ee73732 100644 --- a/lib/payment_services/crypto_apis_v2/blockchain.rb +++ b/lib/payment_services/crypto_apis_v2/blockchain.rb @@ -1,96 +1,99 @@ # frozen_string_literal: true -class PaymentServices::CryptoApisV2 - class Blockchain - API_URL = 'https://rest.cryptoapis.io/v2' - NETWORK = 'mainnet' - CURRENCY_TO_BLOCKCHAIN = { - 'btc' => 'bitcoin', - 'bch' => 'bitcoin-cash', - 'ltc' => 'litecoin', - 'doge' => 'dogecoin', - 'dsh' => 'dash', - 'eth' => 'ethereum', - 'etc' => 'ethereum-classic', - 'bnb' => 'binance-smart-chain', - 'zec' => 'zcash', - 'xrp' => 'xrp' - }.freeze - TOKEN_NETWORK_TO_BLOCKCHAIN = { - 'trc20' => 'tron', - 'bep20' => 'binance-smart-chain', - 'erc20' => 'ethereum' - }.freeze - - ACCOUNT_MODEL_BLOCKCHAINS = %w(ethereum ethereum-classic binance-smart-chain xrp) - FUNGIBLE_TOKENS = %w(usdt) - delegate :xrp?, :bitcoin?, to: :blockchain - - def initialize(currency:, token_network:) - @currency = currency - @token_network = token_network - end - def address_transactions_endpoint(merchant_id:, address:) - if blockchain.xrp? - "#{blockchain_data_prefix}/xrp-specific/#{NETWORK}/addresses/#{address}/transactions" - elsif fungible_token? || currency.inquiry.bnb? - "#{proccess_payout_base_url(merchant_id)}/transactions" - else - "#{blockchain_data_prefix}/#{blockchain}/#{NETWORK}/addresses/#{address}/transactions" +module PaymentServices + class CryptoApisV2 + class Blockchain + API_URL = 'https://rest.cryptoapis.io/v2' + NETWORK = 'mainnet' + CURRENCY_TO_BLOCKCHAIN = { + 'btc' => 'bitcoin', + 'bch' => 'bitcoin-cash', + 'ltc' => 'litecoin', + 'doge' => 'dogecoin', + 'dsh' => 'dash', + 'eth' => 'ethereum', + 'etc' => 'ethereum-classic', + 'bnb' => 'binance-smart-chain', + 'zec' => 'zcash', + 'xrp' => 'xrp' + }.freeze + TOKEN_NETWORK_TO_BLOCKCHAIN = { + 'trc20' => 'tron', + 'bep20' => 'binance-smart-chain', + 'erc20' => 'ethereum' + }.freeze + + ACCOUNT_MODEL_BLOCKCHAINS = %w(ethereum ethereum-classic binance-smart-chain xrp) + FUNGIBLE_TOKENS = %w(usdt) + delegate :xrp?, :bitcoin?, to: :blockchain + + def initialize(currency:, token_network:) + @currency = currency + @token_network = token_network end - end - def transaction_details_endpoint(transaction_id) - if blockchain.xrp? - "#{blockchain_data_prefix}/xrp-specific/#{NETWORK}/transactions/#{transaction_id}" - else - "#{API_URL}/wallet-as-a-service/wallets/#{blockchain}/#{NETWORK}/transactions/#{transaction_id}" - end - end + def address_transactions_endpoint(merchant_id:, address:) + if blockchain.xrp? + "#{blockchain_data_prefix}/xrp-specific/#{NETWORK}/addresses/#{address}/transactions" + elsif fungible_token? || currency.inquiry.bnb? + "#{proccess_payout_base_url(merchant_id)}/transactions" + else + "#{blockchain_data_prefix}/#{blockchain}/#{NETWORK}/addresses/#{address}/transactions" + end + end - def request_details_endpoint(request_id) - "#{API_URL}/wallet-as-a-service/transactionRequests/#{request_id}" - end + def transaction_details_endpoint(transaction_id) + if blockchain.xrp? + "#{blockchain_data_prefix}/xrp-specific/#{NETWORK}/transactions/#{transaction_id}" + else + "#{API_URL}/wallet-as-a-service/wallets/#{blockchain}/#{NETWORK}/transactions/#{transaction_id}" + end + end - def process_payout_endpoint(wallet:) - if blockchain.tron? - "#{proccess_payout_base_url(wallet.merchant_id)}/addresses/#{wallet.account}/feeless-token-transaction-requests" - elsif account_model_blockchain? && currency.inquiry.usdt? - "#{proccess_payout_base_url(wallet.merchant_id)}/addresses/#{wallet.account}/token-transaction-requests" - elsif account_model_blockchain? - "#{proccess_payout_base_url(wallet.merchant_id)}/addresses/#{wallet.account}/transaction-requests" - else - "#{proccess_payout_base_url(wallet.merchant_id)}/transaction-requests" + def request_details_endpoint(request_id) + "#{API_URL}/wallet-as-a-service/transactionRequests/#{request_id}" end - end - def fungible_token? - FUNGIBLE_TOKENS.include?(currency) - end + def process_payout_endpoint(wallet:) + if blockchain.tron? + "#{proccess_payout_base_url(wallet.merchant_id)}/addresses/#{wallet.account}/feeless-token-transaction-requests" + elsif account_model_blockchain? && currency.inquiry.usdt? + "#{proccess_payout_base_url(wallet.merchant_id)}/addresses/#{wallet.account}/token-transaction-requests" + elsif account_model_blockchain? + "#{proccess_payout_base_url(wallet.merchant_id)}/addresses/#{wallet.account}/transaction-requests" + else + "#{proccess_payout_base_url(wallet.merchant_id)}/transaction-requests" + end + end - def account_model_blockchain? - ACCOUNT_MODEL_BLOCKCHAINS.include?(blockchain) - end + def fungible_token? + FUNGIBLE_TOKENS.include?(currency) + end - private + def account_model_blockchain? + ACCOUNT_MODEL_BLOCKCHAINS.include?(blockchain) + end - attr_reader :currency, :token_network + private - def blockchain - @blockchain ||= build_blockchain.inquiry - end + attr_reader :currency, :token_network - def build_blockchain - currency.inquiry.usdt? ? TOKEN_NETWORK_TO_BLOCKCHAIN[token_network] : CURRENCY_TO_BLOCKCHAIN[currency] - end + def blockchain + @blockchain ||= build_blockchain.inquiry + end - def proccess_payout_base_url(merchant_id) - "#{API_URL}/wallet-as-a-service/wallets/#{merchant_id}/#{blockchain}/#{NETWORK}" - end + def build_blockchain + currency.inquiry.usdt? ? TOKEN_NETWORK_TO_BLOCKCHAIN[token_network] : CURRENCY_TO_BLOCKCHAIN[currency] + end - def blockchain_data_prefix - "#{API_URL}/blockchain-data" + def proccess_payout_base_url(merchant_id) + "#{API_URL}/wallet-as-a-service/wallets/#{merchant_id}/#{blockchain}/#{NETWORK}" + end + + def blockchain_data_prefix + "#{API_URL}/blockchain-data" + end end end end diff --git a/lib/payment_services/crypto_apis_v2/client.rb b/lib/payment_services/crypto_apis_v2/client.rb index 3f6344de..292e1a32 100644 --- a/lib/payment_services/crypto_apis_v2/client.rb +++ b/lib/payment_services/crypto_apis_v2/client.rb @@ -2,127 +2,130 @@ require_relative 'blockchain' -class PaymentServices::CryptoApisV2 - class Client < ::PaymentServices::Base::Client - include AutoLogger - - DEFAULT_FEE_PRIORITY = 'standard' - LOW_FEE_PRIORITY = 'slow' - USDT_TRC_FEE_LIMIT = '1000000000' - - def initialize(api_key:, api_secret:, currency:, token_network:) - @api_key = api_key - @api_secret = api_secret - @blockchain = Blockchain.new(currency: currency, token_network: token_network) - end - - def address_transactions(invoice) - safely_parse http_request( - url: blockchain.address_transactions_endpoint(merchant_id: invoice.merchant_id, address: invoice.address), - method: :GET, - headers: build_headers - ) - end - - def transaction_details(transaction_id) - safely_parse http_request( - url: blockchain.transaction_details_endpoint(transaction_id), - method: :GET, - headers: build_headers - ) - end - - def request_details(request_id) - safely_parse http_request( - url: blockchain.request_details_endpoint(request_id), - method: :GET, - headers: build_headers - ) - end - - def make_payout(payout:, wallet_transfers:) - wallet_transfer = wallet_transfers.first - - safely_parse http_request( - url: blockchain.process_payout_endpoint(wallet: wallet_transfer.wallet), - method: :POST, - body: build_payout_request_body(payout: payout, wallet_transfer: wallet_transfer).to_json, - headers: build_headers - ) - end - - def classic_to_x_address(classic_address, address_tag) - return classic_address unless address_tag.present? - - safely_parse(http_request( - url: "https://rest.cryptoapis.io/v2/blockchain-tools/xrp/mainnet/encode-x-address/#{classic_address}/#{address_tag}", - method: :GET, - headers: build_headers - ))['data']['item']['xAddress'] - end - - private - - attr_reader :api_key, :api_secret, :blockchain - - def build_headers - { - 'Content-Type' => 'application/json', - 'Cache-Control' => 'no-cache', - 'X-API-Key' => api_key - } - end - - def build_payout_request_body(payout:, wallet_transfer:) - transaction_body = - if blockchain.fungible_token? - build_fungible_payout_body(payout, wallet_transfer, blockchain) - elsif blockchain.account_model_blockchain? - build_account_payout_body(payout, wallet_transfer) - else - build_utxo_payout_body(payout, wallet_transfer) - end - - { data: { item: transaction_body } } - end - - def build_account_payout_body(payout, wallet_transfer) - body = { - amount: wallet_transfer.amount.to_f.to_s, - feePriority: account_fee_priority, - callbackSecretKey: api_secret, - recipientAddress: payout.address - } - body[:recipientAddress] = classic_to_x_address(body[:recipientAddress], payout.order_fio) if blockchain.xrp? - body - end - - def build_utxo_payout_body(payout, wallet_transfer) - { - callbackSecretKey: api_secret, - feePriority: utxo_fee_priority, - recipients: [{ - address: payout.address, - amount: wallet_transfer.amount.to_f.to_s - }] - } - end - - def build_fungible_payout_body(payout, wallet_transfer, blockchain) - token_address = wallet_transfer.wallet.payment_system.token_address.downcase - - body = build_account_payout_body(payout, wallet_transfer) - .merge(tokenIdentifier: token_address) - blockchain.account_model_blockchain? ? body[:feePriority] = DEFAULT_FEE_PRIORITY : body[:feeLimit] = USDT_TRC_FEE_LIMIT - body - end - - def account_fee_priority - blockchain.fungible_token? || blockchain.xrp? ? LOW_FEE_PRIORITY : DEFAULT_FEE_PRIORITY - end - def utxo_fee_priority - blockchain.bitcoin? ? LOW_FEE_PRIORITY : DEFAULT_FEE_PRIORITY +module PaymentServices + class CryptoApisV2 + class Client < ::PaymentServices::Base::Client + include AutoLogger + + DEFAULT_FEE_PRIORITY = 'standard' + LOW_FEE_PRIORITY = 'slow' + USDT_TRC_FEE_LIMIT = '1000000000' + + def initialize(api_key:, api_secret:, currency:, token_network:) + @api_key = api_key + @api_secret = api_secret + @blockchain = Blockchain.new(currency: currency, token_network: token_network) + end + + def address_transactions(invoice) + safely_parse http_request( + url: blockchain.address_transactions_endpoint(merchant_id: invoice.merchant_id, address: invoice.address), + method: :GET, + headers: build_headers + ) + end + + def transaction_details(transaction_id) + safely_parse http_request( + url: blockchain.transaction_details_endpoint(transaction_id), + method: :GET, + headers: build_headers + ) + end + + def request_details(request_id) + safely_parse http_request( + url: blockchain.request_details_endpoint(request_id), + method: :GET, + headers: build_headers + ) + end + + def make_payout(payout:, wallet_transfers:) + wallet_transfer = wallet_transfers.first + + safely_parse http_request( + url: blockchain.process_payout_endpoint(wallet: wallet_transfer.wallet), + method: :POST, + body: build_payout_request_body(payout: payout, wallet_transfer: wallet_transfer).to_json, + headers: build_headers + ) + end + + def classic_to_x_address(classic_address, address_tag) + return classic_address unless address_tag.present? + + safely_parse(http_request( + url: "https://rest.cryptoapis.io/v2/blockchain-tools/xrp/mainnet/encode-x-address/#{classic_address}/#{address_tag}", + method: :GET, + headers: build_headers + ))['data']['item']['xAddress'] + end + + private + + attr_reader :api_key, :api_secret, :blockchain + + def build_headers + { + 'Content-Type' => 'application/json', + 'Cache-Control' => 'no-cache', + 'X-API-Key' => api_key + } + end + + def build_payout_request_body(payout:, wallet_transfer:) + transaction_body = + if blockchain.fungible_token? + build_fungible_payout_body(payout, wallet_transfer, blockchain) + elsif blockchain.account_model_blockchain? + build_account_payout_body(payout, wallet_transfer) + else + build_utxo_payout_body(payout, wallet_transfer) + end + + { data: { item: transaction_body } } + end + + def build_account_payout_body(payout, wallet_transfer) + body = { + amount: wallet_transfer.amount.to_f.to_s, + feePriority: account_fee_priority, + callbackSecretKey: api_secret, + recipientAddress: payout.address + } + body[:recipientAddress] = classic_to_x_address(body[:recipientAddress], payout.order_fio) if blockchain.xrp? + body + end + + def build_utxo_payout_body(payout, wallet_transfer) + { + callbackSecretKey: api_secret, + feePriority: utxo_fee_priority, + recipients: [{ + address: payout.address, + amount: wallet_transfer.amount.to_f.to_s + }] + } + end + + def build_fungible_payout_body(payout, wallet_transfer, blockchain) + token_address = wallet_transfer.wallet.payment_system.token_address.downcase + + body = build_account_payout_body(payout, wallet_transfer) + .merge(tokenIdentifier: token_address) + blockchain.account_model_blockchain? ? body[:feePriority] = DEFAULT_FEE_PRIORITY : body[:feeLimit] = USDT_TRC_FEE_LIMIT + body + end + + def account_fee_priority + blockchain.fungible_token? || blockchain.xrp? ? LOW_FEE_PRIORITY : DEFAULT_FEE_PRIORITY + end + + def utxo_fee_priority + blockchain.bitcoin? ? LOW_FEE_PRIORITY : DEFAULT_FEE_PRIORITY + end end end end diff --git a/lib/payment_services/crypto_apis_v2/invoice.rb b/lib/payment_services/crypto_apis_v2/invoice.rb index 9f2dcbb1..d77e30e9 100644 --- a/lib/payment_services/crypto_apis_v2/invoice.rb +++ b/lib/payment_services/crypto_apis_v2/invoice.rb @@ -1,56 +1,59 @@ # frozen_string_literal: true -class PaymentServices::CryptoApisV2 - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'crypto_apis_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class CryptoApisV2 + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'crypto_apis_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :has_transaction, transitions_to: :with_transaction - end - state :with_transaction do - on_entry do - order.make_reserve! + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :has_transaction, transitions_to: :with_transaction + end + state :with_transaction do + on_entry do + order.make_reserve! + end + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled end - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - def update_invoice_details!(transaction:) - has_transaction! if pending? - update!( - transaction_created_at: transaction.created_at, - transaction_id: transaction.id, - confirmed: transaction.confirmed? - ) - pay!(payload: transaction) if confirmed? - end + def update_invoice_details!(transaction:) + has_transaction! if pending? + update!( + transaction_created_at: transaction.created_at, + transaction_id: transaction.id, + confirmed: transaction.confirmed? + ) + pay!(payload: transaction) if confirmed? + end - def merchant_id - @merchant_id ||= order.income_wallet.merchant_id + def merchant_id + @merchant_id ||= order.income_wallet.merchant_id + end end end end diff --git a/lib/payment_services/crypto_apis_v2/invoicer.rb b/lib/payment_services/crypto_apis_v2/invoicer.rb index a19e5344..0824a70f 100644 --- a/lib/payment_services/crypto_apis_v2/invoicer.rb +++ b/lib/payment_services/crypto_apis_v2/invoicer.rb @@ -4,46 +4,49 @@ require_relative 'client' require_relative 'transaction_repository' -class PaymentServices::CryptoApisV2 - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end - def update_invoice_state! - transaction = transaction_for(invoice) - return if transaction.nil? +module PaymentServices + class CryptoApisV2 + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - invoice.update_invoice_details!(transaction: transaction) - end + def update_invoice_state! + transaction = transaction_for(invoice) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update_invoice_details!(transaction: transaction) + end - def async_invoice_state_updater? - true - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - private + def async_invoice_state_updater? + true + end - def transaction_for(invoice) - TransactionRepository.new(collect_transactions).find_for(invoice) - end + private - def collect_transactions - response = client.address_transactions(invoice) - raise response['error']['message'] if response['error'] + def transaction_for(invoice) + TransactionRepository.new(collect_transactions).find_for(invoice) + end - response['data']['items'] - end + def collect_transactions + response = client.address_transactions(invoice) + raise response['error']['message'] if response['error'] - def wallet - @wallet ||= order.income_wallet - end + response['data']['items'] + end + + def wallet + @wallet ||= order.income_wallet + end - def client - @client ||= Client.new(api_key: api_key, api_secret: api_secret, currency: wallet.currency.to_s.downcase, token_network: wallet.payment_system.token_network) + def client + @client ||= Client.new(api_key: api_key, api_secret: api_secret, currency: wallet.currency.to_s.downcase, token_network: wallet.payment_system.token_network) + end end end end diff --git a/lib/payment_services/crypto_apis_v2/payout.rb b/lib/payment_services/crypto_apis_v2/payout.rb index 648fd4f9..d9a7bb06 100644 --- a/lib/payment_services/crypto_apis_v2/payout.rb +++ b/lib/payment_services/crypto_apis_v2/payout.rb @@ -1,44 +1,47 @@ # frozen_string_literal: true -class PaymentServices::CryptoApisV2 - class Payout < ApplicationRecord - include Workflow - self.table_name = 'crypto_apis_payouts' - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :address, :fee, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed +module PaymentServices + class CryptoApisV2 + class Payout < ApplicationRecord + include Workflow + self.table_name = 'crypto_apis_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :address, :fee, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(request_id:) - update(request_id: request_id) - end + def pay(request_id:) + update(request_id: request_id) + end - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) - end + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end - def order_fio - order_payout.order.outcome_fio.presence || order_payout.order.outcome_unk - end + def order_fio + order_payout.order.outcome_fio.presence || order_payout.order.outcome_unk + end - def update_payout_details!(transaction:) - update!(confirmed: transaction.confirmed?, fee: transaction.fee) + def update_payout_details!(transaction:) + update!(confirmed: transaction.confirmed?, fee: transaction.fee) - confirm! if confirmed? + confirm! if confirmed? + end end end end diff --git a/lib/payment_services/crypto_apis_v2/payout_adapter.rb b/lib/payment_services/crypto_apis_v2/payout_adapter.rb index 1d4deab4..d8345c1f 100644 --- a/lib/payment_services/crypto_apis_v2/payout_adapter.rb +++ b/lib/payment_services/crypto_apis_v2/payout_adapter.rb @@ -4,63 +4,66 @@ require_relative 'client' require_relative 'transaction' -class PaymentServices::CryptoApisV2 - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - FAILED_PAYOUT_STATUSES = %w(failed rejected) - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - raise 'amount is not a Money' unless amount.is_a? Money - - make_payout( - amount: amount, - address: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class CryptoApisV2 + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + FAILED_PAYOUT_STATUSES = %w(failed rejected) - unless payout.txid - response = client.request_details(payout.request_id) - raise response['error']['message'] if response['error'] + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + raise 'amount is not a Money' unless amount.is_a? Money - transaction = response['data']['item'] - payout.fail! if FAILED_PAYOUT_STATUSES.include?(transaction['transactionRequestStatus']) - payout.update!(txid: transaction['transactionId']) if transaction['transactionId'] - else - response = client.transaction_details(payout.txid) - raise response['error']['message'] if response['error'] - - payout.update_payout_details!(transaction: build_transaction(source: response['data']['item'])) + make_payout( + amount: amount, + address: destination_account, + order_payout_id: order_payout_id + ) end - response - end + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - private + unless payout.txid + response = client.request_details(payout.request_id) + raise response['error']['message'] if response['error'] - def make_payout(amount:, address:, order_payout_id:) - payout = create_payout!(amount: amount, address: address, fee: 0, order_payout_id: order_payout_id) + transaction = response['data']['item'] + payout.fail! if FAILED_PAYOUT_STATUSES.include?(transaction['transactionRequestStatus']) + payout.update!(txid: transaction['transactionId']) if transaction['transactionId'] + else + response = client.transaction_details(payout.txid) + raise response['error']['message'] if response['error'] - response = client.make_payout(payout: payout, wallet_transfers: wallet_transfers) - raise response['error']['message'] if response['error'] + payout.update_payout_details!(transaction: build_transaction(source: response['data']['item'])) + end - request_id = response['data']['item']['transactionRequestId'] - payout.pay!(request_id: request_id) - end + response + end - def client - @client ||= Client.new(api_key: api_key, api_secret: api_secret, currency: wallet.currency.to_s.downcase, token_network: wallet.payment_system.token_network) - end + private - def create_payout!(amount:, address:, fee:, order_payout_id:) - Payout.create!(amount: amount, address: address, fee: fee, order_payout_id: order_payout_id) - end + def make_payout(amount:, address:, order_payout_id:) + payout = create_payout!(amount: amount, address: address, fee: 0, order_payout_id: order_payout_id) - def build_transaction(source:) - Transaction.build_from(transaction_hash: source['transactionHash'], created_at: source['transactionTimestamp'], currency: wallet.currency.to_s.downcase, source: source) + response = client.make_payout(payout: payout, wallet_transfers: wallet_transfers) + raise response['error']['message'] if response['error'] + + request_id = response['data']['item']['transactionRequestId'] + payout.pay!(request_id: request_id) + end + + def client + @client ||= Client.new(api_key: api_key, api_secret: api_secret, currency: wallet.currency.to_s.downcase, token_network: wallet.payment_system.token_network) + end + + def create_payout!(amount:, address:, fee:, order_payout_id:) + Payout.create!(amount: amount, address: address, fee: fee, order_payout_id: order_payout_id) + end + + def build_transaction(source:) + Transaction.build_from(transaction_hash: source['transactionHash'], created_at: source['transactionTimestamp'], currency: wallet.currency.to_s.downcase, source: source) + end end end end diff --git a/lib/payment_services/crypto_apis_v2/transaction.rb b/lib/payment_services/crypto_apis_v2/transaction.rb index 14f19567..c293d342 100644 --- a/lib/payment_services/crypto_apis_v2/transaction.rb +++ b/lib/payment_services/crypto_apis_v2/transaction.rb @@ -1,67 +1,70 @@ # frozen_string_literal: true -class PaymentServices::CryptoApisV2 - class Transaction - SUCCESS_XRP_STATUS = 'tesSUCCESS' - - include Virtus.model - - attribute :id, String - attribute :created_at, DateTime - attribute :currency, String - attribute :source, Hash - - def self.build_from(transaction_hash:, created_at:, currency:, source:) - new( - id: transaction_hash, - created_at: created_at, - currency: currency, - source: source - ) - end - def to_s - source.to_s - end +module PaymentServices + class CryptoApisV2 + class Transaction + SUCCESS_XRP_STATUS = 'tesSUCCESS' - def confirmed? - send("#{currency}_transaction_confirmed?") - end + include Virtus.model - def fee - source.dig('fee', 'amount') || 0 - end + attribute :id, String + attribute :created_at, DateTime + attribute :currency, String + attribute :source, Hash - private + def self.build_from(transaction_hash:, created_at:, currency:, source:) + new( + id: transaction_hash, + created_at: created_at, + currency: currency, + source: source + ) + end - def method_missing(method_name) - super unless method_name.end_with?('_transaction_confirmed?') + def to_s + source.to_s + end - generic_transaction_confirmed? - end + def confirmed? + send("#{currency}_transaction_confirmed?") + end - def generic_transaction_confirmed? - source['minedInBlockHeight'] > 0 - end + def fee + source.dig('fee', 'amount') || 0 + end - def btc_transaction_confirmed? - source['isConfirmed'] - end + private - def xrp_transaction_confirmed? - status == SUCCESS_XRP_STATUS - end + def method_missing(method_name) + super unless method_name.end_with?('_transaction_confirmed?') - def bnb_transaction_confirmed? - source['isConfirmed'] - end + generic_transaction_confirmed? + end - def usdt_transaction_confirmed? - source['isConfirmed'] - end + def generic_transaction_confirmed? + source['minedInBlockHeight'] > 0 + end + + def btc_transaction_confirmed? + source['isConfirmed'] + end + + def xrp_transaction_confirmed? + status == SUCCESS_XRP_STATUS + end + + def bnb_transaction_confirmed? + source['isConfirmed'] + end + + def usdt_transaction_confirmed? + source['isConfirmed'] + end - def status - source['status'].inquiry + def status + source['status'].inquiry + end end end end diff --git a/lib/payment_services/crypto_apis_v2/transaction_repository.rb b/lib/payment_services/crypto_apis_v2/transaction_repository.rb index 84dda814..13b8efda 100644 --- a/lib/payment_services/crypto_apis_v2/transaction_repository.rb +++ b/lib/payment_services/crypto_apis_v2/transaction_repository.rb @@ -3,135 +3,138 @@ require_relative 'transaction' require_relative 'blockchain' -class PaymentServices::CryptoApisV2 - class TransactionRepository - TRANSACTION_TIME_THRESHOLD = 30.minutes - BASIC_TIME_COUNTDOWN = 1.minute - def initialize(transactions) - @transactions = transactions - end - - def find_for(invoice) - @invoice = invoice - send("find_#{invoice.amount_currency.downcase}_transaction") - end - - private - - attr_reader :invoice, :transactions - - def currency - @currency ||= wallet.currency.to_s.downcase - end - - def wallet - @wallet ||= invoice.order.income_wallet - end - - def build_transaction(id:, created_at:, currency:, source:) - Transaction.build_from(transaction_hash: id, created_at: created_at, currency: currency, source: source) - end - - def method_missing(method_name) - super unless method_name.start_with?('find_') && method_name.end_with?('_transaction') - - raw_transaction = transactions.find { |transaction| find_generic_transaction?(transaction) } - return unless raw_transaction - - build_transaction( - id: raw_transaction['transactionHash'], - created_at: timestamp_in_utc(raw_transaction['timestamp']), - currency: currency, - source: raw_transaction - ) - end - - def find_generic_transaction?(transaction) - amount = parse_received_amount(transaction) - transaction_created_at = timestamp_in_utc(transaction['timestamp']) - invoice_created_at = invoice.created_at.utc - - time_diff = (transaction_created_at - invoice_created_at) / BASIC_TIME_COUNTDOWN - invoice_created_at < transaction_created_at && match_by_amount_and_time?(amount, time_diff) - end - - def find_usdt_transaction - raw_transaction = transactions.find { |transaction| find_token?(transaction) } - return unless raw_transaction - - build_transaction( - id: raw_transaction['transactionId'], - created_at: timestamp_in_utc(raw_transaction['timestamp']), - currency: currency, - source: raw_transaction - ) - end - - def find_bnb_transaction - raw_transaction = transactions.find { |transaction| find_bnb_token?(transaction) } - return unless raw_transaction - - build_transaction( - id: raw_transaction['transactionId'], - created_at: timestamp_in_utc(raw_transaction['timestamp']), - currency: currency, - source: raw_transaction - ) - end - - def match_by_amount_and_time?(amount, time_diff) - match_amount?(amount) && match_transaction_time_threshold?(time_diff) - end - - def match_amount?(received_amount) - received_amount.to_d == invoice.amount.to_d - end - - def match_transaction_time_threshold?(time_diff) - time_diff.round.minutes < TRANSACTION_TIME_THRESHOLD - end - - def find_token?(transaction) - amount = parse_tokens_amount(transaction) - transaction_created_at = timestamp_in_utc(transaction['timestamp']) - invoice_created_at = invoice.created_at.utc - - time_diff = (transaction_created_at - invoice_created_at) / BASIC_TIME_COUNTDOWN - invoice_created_at < transaction_created_at && match_by_amount_and_time?(amount, time_diff) && match_by_contract_address?(transaction) - end - - def find_bnb_token?(transaction) - amount = parse_bnb_tokens_amount(transaction) - transaction_created_at = timestamp_in_utc(transaction['timestamp']) - invoice_created_at = invoice.created_at.utc - - time_diff = (transaction_created_at - invoice_created_at) / BASIC_TIME_COUNTDOWN - invoice_created_at < transaction_created_at && match_by_amount_and_time?(amount, time_diff) - end - - def match_by_contract_address?(transaction) - transaction['fungibleTokens'].first['type'].tr('-','') == wallet.payment_system.token_network.upcase - end - - def parse_received_amount(transaction) - recipient = transaction['recipients'].find { |recipient| recipient['address'].include?(invoice.address) } - recipient ? recipient['amount'] : 0 - end - - def parse_tokens_amount(transaction) - tokens = transaction['fungibleTokens'].first - return 0 unless tokens.is_a? Hash - tokens['recipient'] == invoice.address ? tokens['amount'] : 0 - end - - def parse_bnb_tokens_amount(transaction) - recipient = transaction['recipients'].find { |recipient| recipient['address'] == invoice.address } - recipient ? recipient['amount'] : 0 - end - - def timestamp_in_utc(timestamp) - DateTime.strptime(timestamp.to_s,'%s').utc +module PaymentServices + class CryptoApisV2 + class TransactionRepository + TRANSACTION_TIME_THRESHOLD = 30.minutes + BASIC_TIME_COUNTDOWN = 1.minute + + def initialize(transactions) + @transactions = transactions + end + + def find_for(invoice) + @invoice = invoice + send("find_#{invoice.amount_currency.downcase}_transaction") + end + + private + + attr_reader :invoice, :transactions + + def currency + @currency ||= wallet.currency.to_s.downcase + end + + def wallet + @wallet ||= invoice.order.income_wallet + end + + def build_transaction(id:, created_at:, currency:, source:) + Transaction.build_from(transaction_hash: id, created_at: created_at, currency: currency, source: source) + end + + def method_missing(method_name) + super unless method_name.start_with?('find_') && method_name.end_with?('_transaction') + + raw_transaction = transactions.find { |transaction| find_generic_transaction?(transaction) } + return unless raw_transaction + + build_transaction( + id: raw_transaction['transactionHash'], + created_at: timestamp_in_utc(raw_transaction['timestamp']), + currency: currency, + source: raw_transaction + ) + end + + def find_generic_transaction?(transaction) + amount = parse_received_amount(transaction) + transaction_created_at = timestamp_in_utc(transaction['timestamp']) + invoice_created_at = invoice.created_at.utc + + time_diff = (transaction_created_at - invoice_created_at) / BASIC_TIME_COUNTDOWN + invoice_created_at < transaction_created_at && match_by_amount_and_time?(amount, time_diff) + end + + def find_usdt_transaction + raw_transaction = transactions.find { |transaction| find_token?(transaction) } + return unless raw_transaction + + build_transaction( + id: raw_transaction['transactionId'], + created_at: timestamp_in_utc(raw_transaction['timestamp']), + currency: currency, + source: raw_transaction + ) + end + + def find_bnb_transaction + raw_transaction = transactions.find { |transaction| find_bnb_token?(transaction) } + return unless raw_transaction + + build_transaction( + id: raw_transaction['transactionId'], + created_at: timestamp_in_utc(raw_transaction['timestamp']), + currency: currency, + source: raw_transaction + ) + end + + def match_by_amount_and_time?(amount, time_diff) + match_amount?(amount) && match_transaction_time_threshold?(time_diff) + end + + def match_amount?(received_amount) + received_amount.to_d == invoice.amount.to_d + end + + def match_transaction_time_threshold?(time_diff) + time_diff.round.minutes < TRANSACTION_TIME_THRESHOLD + end + + def find_token?(transaction) + amount = parse_tokens_amount(transaction) + transaction_created_at = timestamp_in_utc(transaction['timestamp']) + invoice_created_at = invoice.created_at.utc + + time_diff = (transaction_created_at - invoice_created_at) / BASIC_TIME_COUNTDOWN + invoice_created_at < transaction_created_at && match_by_amount_and_time?(amount, time_diff) && match_by_contract_address?(transaction) + end + + def find_bnb_token?(transaction) + amount = parse_bnb_tokens_amount(transaction) + transaction_created_at = timestamp_in_utc(transaction['timestamp']) + invoice_created_at = invoice.created_at.utc + + time_diff = (transaction_created_at - invoice_created_at) / BASIC_TIME_COUNTDOWN + invoice_created_at < transaction_created_at && match_by_amount_and_time?(amount, time_diff) + end + + def match_by_contract_address?(transaction) + transaction['fungibleTokens'].first['type'].tr('-','') == wallet.payment_system.token_network.upcase + end + + def parse_received_amount(transaction) + recipient = transaction['recipients'].find { |recipient| recipient['address'].include?(invoice.address) } + recipient ? recipient['amount'] : 0 + end + + def parse_tokens_amount(transaction) + tokens = transaction['fungibleTokens'].first + return 0 unless tokens.is_a? Hash + tokens['recipient'] == invoice.address ? tokens['amount'] : 0 + end + + def parse_bnb_tokens_amount(transaction) + recipient = transaction['recipients'].find { |recipient| recipient['address'] == invoice.address } + recipient ? recipient['amount'] : 0 + end + + def timestamp_in_utc(timestamp) + DateTime.strptime(timestamp.to_s,'%s').utc + end end end end diff --git a/lib/payment_services/cryptomus/client.rb b/lib/payment_services/cryptomus/client.rb index adf75fdb..c801f72f 100644 --- a/lib/payment_services/cryptomus/client.rb +++ b/lib/payment_services/cryptomus/client.rb @@ -1,73 +1,76 @@ # frozen_string_literal: true -class PaymentServices::Cryptomus - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.heleket.com/v1' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Cryptomus + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.heleket.com/v1' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payment", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def create_payout(params:) - safely_parse http_request( - url: "#{API_URL}/payout", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payment", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payment/info", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_payout(params:) + safely_parse http_request( + url: "#{API_URL}/payout", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def payout(params:) - safely_parse http_request( - url: "#{API_URL}/payout/info", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payment/info", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def fee - safely_parse http_request( - url: "#{API_URL}/payout/services", - method: :POST, - body: {}.to_json, - headers: build_headers(signature: build_signature) - ) - end + def payout(params:) + safely_parse http_request( + url: "#{API_URL}/payout/info", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - private + def fee + safely_parse http_request( + url: "#{API_URL}/payout/services", + method: :POST, + body: {}.to_json, + headers: build_headers(signature: build_signature) + ) + end - attr_reader :api_key, :secret_key + private - def build_signature(params = {}) - Digest::MD5.hexdigest(Base64.encode64(params.to_json).gsub(/\n/, '') + secret_key) - end + attr_reader :api_key, :secret_key + + def build_signature(params = {}) + Digest::MD5.hexdigest(Base64.encode64(params.to_json).gsub(/\n/, '') + secret_key) + end - def build_headers(signature:) - { - 'merchant' => api_key, - 'sign' => signature, - 'Content-Type' => 'application/json' - } + def build_headers(signature:) + { + 'merchant' => api_key, + 'sign' => signature, + 'Content-Type' => 'application/json' + } + end end end end diff --git a/lib/payment_services/cryptomus/invoice.rb b/lib/payment_services/cryptomus/invoice.rb index 9b3eb418..a58e2836 100644 --- a/lib/payment_services/cryptomus/invoice.rb +++ b/lib/payment_services/cryptomus/invoice.rb @@ -1,41 +1,44 @@ # frozen_string_literal: true -class PaymentServices::Cryptomus - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATES = %w(paid paid_over wrong_amount_waiting wrong_amount) - FAILED_PROVIDER_STATES = %w(fail cancel system_fail) - self.table_name = 'cryptomus_invoices' +module PaymentServices + class Cryptomus + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATES = %w(paid paid_over wrong_amount_waiting wrong_amount) + FAILED_PROVIDER_STATES = %w(fail cancel system_fail) - monetize :amount_cents, as: :amount + self.table_name = 'cryptomus_invoices' - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + monetize :amount_cents, as: :amount + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def transaction_created_at - nil - end + def transaction_created_at + nil + end - private + private - def provider_succeed? - provider_state.in? SUCCESS_PROVIDER_STATES - end + def provider_succeed? + provider_state.in? SUCCESS_PROVIDER_STATES + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/cryptomus/invoicer.rb b/lib/payment_services/cryptomus/invoicer.rb index 0d941857..37d22cd0 100644 --- a/lib/payment_services/cryptomus/invoicer.rb +++ b/lib/payment_services/cryptomus/invoicer.rb @@ -3,87 +3,90 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Cryptomus - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - USDT_NETWORK_TO_CURRENCY = { - 'trc20' => 'TRON', - 'erc20' => 'ETH', - 'ton' => 'TON', - 'sol' => 'SOL', - 'POLYGON' => 'POLYGON', - 'bep20' => 'BSC' - }.freeze - - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise Error, "Can't create invoice: #{response['message']}" if response['message'] - - invoice.update!(deposit_id: response.dig('result', 'uuid')) - PaymentServices::Base::Wallet.new( - address: response.dig('result', 'address'), - name: nil - ) - end - def create_invoice(money) - invoice - end +module PaymentServices + class Cryptomus + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + USDT_NETWORK_TO_CURRENCY = { + 'trc20' => 'TRON', + 'erc20' => 'ETH', + 'ton' => 'TON', + 'sol' => 'SOL', + 'POLYGON' => 'POLYGON', + 'bep20' => 'BSC' + }.freeze + + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise Error, "Can't create invoice: #{response['message']}" if response['message'] + + invoice.update!(deposit_id: response.dig('result', 'uuid')) + PaymentServices::Base::Wallet.new( + address: response.dig('result', 'address'), + name: nil + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.invoice(params: { uuid: invoice.deposit_id }) - return if transaction.dig('result', 'payment_amount').nil? + def async_invoice_state_updater? + true + end + + def update_invoice_state! + transaction = client.invoice(params: { uuid: invoice.deposit_id }) + return if transaction.dig('result', 'payment_amount').nil? - status = transaction.dig('result', 'payment_status') - if status.in?(Invoice::SUCCESS_PROVIDER_STATES) - recalculate_order(transaction) if recalculate_on_different_amount + status = transaction.dig('result', 'payment_status') + if status.in?(Invoice::SUCCESS_PROVIDER_STATES) + recalculate_order(transaction) if recalculate_on_different_amount + end + invoice.update_state_by_provider(status) end - invoice.update_state_by_provider(status) - end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - private + private - delegate :token_network, :recalculate_on_different_amount, to: :income_payment_system - delegate :income_payment_system, to: :order + delegate :token_network, :recalculate_on_different_amount, to: :income_payment_system + delegate :income_payment_system, to: :order - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def invoice_params - currency = invoice.amount_currency.to_s.downcase.inquiry - currency = 'dash'.inquiry if currency.dsh? - params = { - amount: invoice.amount.to_f.to_s, - currency: currency.upcase, - order_id: order.public_id.to_s, - lifetime: order.income_payment_timeout.to_i - } - params[:network] = currency.usdt? || currency.bnb? ? network(currency) : currency.upcase - params - end + def invoice_params + currency = invoice.amount_currency.to_s.downcase.inquiry + currency = 'dash'.inquiry if currency.dsh? + params = { + amount: invoice.amount.to_f.to_s, + currency: currency.upcase, + order_id: order.public_id.to_s, + lifetime: order.income_payment_timeout.to_i + } + params[:network] = currency.usdt? || currency.bnb? ? network(currency) : currency.upcase + params + end - def network(currency) - return 'BSC' if currency.bnb? + def network(currency) + return 'BSC' if currency.bnb? - USDT_NETWORK_TO_CURRENCY[token_network] || 'USDT' - end + USDT_NETWORK_TO_CURRENCY[token_network] || 'USDT' + end - def recalculate_order(transaction) - order.operator_recalculate!(transaction.dig('result', 'payment_amount')) - end + def recalculate_order(transaction) + order.operator_recalculate!(transaction.dig('result', 'payment_amount')) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/cryptomus/payout.rb b/lib/payment_services/cryptomus/payout.rb index ddbe4816..16656496 100644 --- a/lib/payment_services/cryptomus/payout.rb +++ b/lib/payment_services/cryptomus/payout.rb @@ -1,19 +1,22 @@ # frozen_string_literal: true -class PaymentServices::Cryptomus - class Payout < ::PaymentServices::Base::FiatPayout - self.table_name = 'cryptomus_payouts' - monetize :amount_cents, as: :amount +module PaymentServices + class Cryptomus + class Payout < ::PaymentServices::Base::FiatPayout + self.table_name = 'cryptomus_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state.in? Invoice::SUCCESS_PROVIDER_STATES - end + private + + def provider_succeed? + provider_state.in? Invoice::SUCCESS_PROVIDER_STATES + end - def provider_failed? - provider_state.in? Invoice::FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? Invoice::FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/cryptomus/payout_adapter.rb b/lib/payment_services/cryptomus/payout_adapter.rb index 411090f3..1408b27f 100644 --- a/lib/payment_services/cryptomus/payout_adapter.rb +++ b/lib/payment_services/cryptomus/payout_adapter.rb @@ -3,85 +3,88 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Cryptomus - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - Error = Class.new StandardError - USDT_NETWORK_TO_CURRENCY = { - 'trc20' => 'TRON', - 'erc20' => 'ETH', - 'ton' => 'TON', - 'sol' => 'SOL', - 'POLYGON' => 'POLYGON', - 'bep20' => 'BSC' - }.freeze - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? - - transaction = client.payout(params: { uuid: payout.withdrawal_id } ) - payout.update(txid: transaction.dig('result', 'txid')) - payout.update_state_by_provider(transaction.dig('result', 'status')) - transaction - end - - private - - attr_reader :payout - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise Error, "Can't create payout: #{response['message']}" if response['message'] - - payout.pay!(withdrawal_id: response.dig('result', 'uuid')) - end - - def payout_params - currency = payout.amount_currency.to_s.downcase.inquiry - currency = 'dash'.inquiry if currency.dsh? - network = currency.usdt? || currency.bnb? ? network(currency) : currency.upcase - params = { - amount: (payout.amount.to_f + fee_by(currency: currency.upcase, network: network)).to_d.to_s, - currency: currency.upcase, - network: network, - order_id: order.public_id.to_s, - address: payout.destination_account, - is_subtract: true - } - params[:memo] = order.outcome_fio if currency.ton? - params - end - - def network(currency) - return 'BSC' if currency.bnb? - - USDT_NETWORK_TO_CURRENCY[order.outcome_payment_system.token_network] || 'USDT' - end - - def order - @order ||= OrderPayout.find(payout.order_payout_id).order - end - - def fee - @fee ||= client.fee['result'] - end - - def fee_by(currency:, network:) - 0 - # fee.find { |e| e['network'] == network && e['currency'] == currency }&.dig('commission', 'fee_amount').to_f - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class Cryptomus + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + Error = Class.new StandardError + USDT_NETWORK_TO_CURRENCY = { + 'trc20' => 'TRON', + 'erc20' => 'ETH', + 'ton' => 'TON', + 'sol' => 'SOL', + 'POLYGON' => 'POLYGON', + 'bep20' => 'BSC' + }.freeze + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? + + transaction = client.payout(params: { uuid: payout.withdrawal_id } ) + payout.update(txid: transaction.dig('result', 'txid')) + payout.update_state_by_provider(transaction.dig('result', 'status')) + transaction + end + + private + + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise Error, "Can't create payout: #{response['message']}" if response['message'] + + payout.pay!(withdrawal_id: response.dig('result', 'uuid')) + end + + def payout_params + currency = payout.amount_currency.to_s.downcase.inquiry + currency = 'dash'.inquiry if currency.dsh? + network = currency.usdt? || currency.bnb? ? network(currency) : currency.upcase + params = { + amount: (payout.amount.to_f + fee_by(currency: currency.upcase, network: network)).to_d.to_s, + currency: currency.upcase, + network: network, + order_id: order.public_id.to_s, + address: payout.destination_account, + is_subtract: true + } + params[:memo] = order.outcome_fio if currency.ton? + params + end + + def network(currency) + return 'BSC' if currency.bnb? + + USDT_NETWORK_TO_CURRENCY[order.outcome_payment_system.token_network] || 'USDT' + end + + def order + @order ||= OrderPayout.find(payout.order_payout_id).order + end + + def fee + @fee ||= client.fee['result'] + end + + def fee_by(currency:, network:) + 0 + # fee.find { |e| e['network'] == network && e['currency'] == currency }&.dig('commission', 'fee_amount').to_f + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/erapay/client.rb b/lib/payment_services/erapay/client.rb index 309d94fd..41836d1e 100644 --- a/lib/payment_services/erapay/client.rb +++ b/lib/payment_services/erapay/client.rb @@ -1,31 +1,34 @@ # frozen_string_literal: true -class PaymentServices::Erapay - class Client < ::PaymentServices::Base::Client - API_URL = 'https://erapay.ru/api' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Erapay + class Client < ::PaymentServices::Base::Client + API_URL = 'https://erapay.ru/api' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/createOrder", - method: :POST, - body: URI.encode_www_form(params.merge(token: api_key, shop_id: secret_key)), - headers: build_headers - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/createOrder", + method: :POST, + body: URI.encode_www_form(params.merge(token: api_key, shop_id: secret_key)), + headers: build_headers + ) + end - private + private - attr_reader :api_key, :secret_key + attr_reader :api_key, :secret_key - def build_headers - { - 'Content-Type' => 'application/x-www-form-urlencoded' - } + def build_headers + { + 'Content-Type' => 'application/x-www-form-urlencoded' + } + end end end end diff --git a/lib/payment_services/erapay/invoice.rb b/lib/payment_services/erapay/invoice.rb index 89e78e61..1ed2a057 100644 --- a/lib/payment_services/erapay/invoice.rb +++ b/lib/payment_services/erapay/invoice.rb @@ -1,25 +1,28 @@ # frozen_string_literal: true -class PaymentServices::Erapay - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = '0' - self.table_name = 'erapay_invoices' +module PaymentServices + class Erapay + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = '0' - monetize :amount_cents, as: :amount + self.table_name = 'erapay_invoices' - def can_be_confirmed?(income_money:, status:) - pending? && status == SUCCESS_PROVIDER_STATE && income_money == amount - end + monetize :amount_cents, as: :amount - private + def can_be_confirmed?(income_money:, status:) + pending? && status == SUCCESS_PROVIDER_STATE && income_money == amount + end - def provider_succeed? - false - end + private + + def provider_succeed? + false + end - def provider_failed? - false + def provider_failed? + false + end end end end diff --git a/lib/payment_services/erapay/invoicer.rb b/lib/payment_services/erapay/invoicer.rb index 729e7882..70383e25 100644 --- a/lib/payment_services/erapay/invoicer.rb +++ b/lib/payment_services/erapay/invoicer.rb @@ -3,54 +3,57 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Erapay - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) +module PaymentServices + class Erapay + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError - raise Error, "Can't create invoice: #{response['data']['message']}" if response['data']['message'].present? + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) - invoice.update!( - deposit_id: response.dig('data', 'info', 'order_id'), - pay_url: response['data']['link'] - ) - end + raise Error, "Can't create invoice: #{response['data']['message']}" if response['data']['message'].present? - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end + invoice.update!( + deposit_id: response.dig('data', 'info', 'order_id'), + pay_url: response['data']['link'] + ) + end - def async_invoice_state_updater? - false - end + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def async_invoice_state_updater? + false + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :sbp?, to: :bank_resolver + private - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + delegate :sbp?, to: :bank_resolver - def invoice_params - { - unique_id: order.public_id.to_s, - amount: invoice.amount.to_i, - description: "Order ##{order.public_id.to_s}", - user_ip: order.remote_ip, - system_name: sbp? ? 'sbp' : 'card' - } - end + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end + + def invoice_params + { + unique_id: order.public_id.to_s, + amount: invoice.amount.to_i, + description: "Order ##{order.public_id.to_s}", + user_ip: order.remote_ip, + system_name: sbp? ? 'sbp' : 'card' + } + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/ex_pay/client.rb b/lib/payment_services/ex_pay/client.rb index 43b0cae8..65b4f75c 100644 --- a/lib/payment_services/ex_pay/client.rb +++ b/lib/payment_services/ex_pay/client.rb @@ -1,61 +1,64 @@ # frozen_string_literal: true -class PaymentServices::ExPay - class Client < ::PaymentServices::Base::Client - API_URL = 'https://apiv2.expay.cash/api/transaction' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class ExPay + class Client < ::PaymentServices::Base::Client + API_URL = 'https://apiv2.expay.cash/api/transaction' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/create/in", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def create_payout(params:) - safely_parse http_request( - url: "#{API_URL}/create/out", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/create/in", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def transaction(tracker_id:) - params = { tracker_id: tracker_id } - safely_parse(http_request( - url: "#{API_URL}/get", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ))['transaction'] - end + def create_payout(params:) + safely_parse http_request( + url: "#{API_URL}/create/out", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - private + def transaction(tracker_id:) + params = { tracker_id: tracker_id } + safely_parse(http_request( + url: "#{API_URL}/get", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ))['transaction'] + end - attr_reader :api_key, :secret_key + private - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'ApiPublic' => api_key, - 'TimeStamp' => timestamp_string, - 'Signature' => signature - } - end + attr_reader :api_key, :secret_key - def build_signature(params) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, timestamp_string + params.to_json) - end + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'ApiPublic' => api_key, + 'TimeStamp' => timestamp_string, + 'Signature' => signature + } + end + + def build_signature(params) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, timestamp_string + params.to_json) + end - def timestamp_string - @timestamp_string ||= Time.now.to_i.to_s + def timestamp_string + @timestamp_string ||= Time.now.to_i.to_s + end end end end diff --git a/lib/payment_services/ex_pay/invoice.rb b/lib/payment_services/ex_pay/invoice.rb index ae6809ae..bd9dd381 100644 --- a/lib/payment_services/ex_pay/invoice.rb +++ b/lib/payment_services/ex_pay/invoice.rb @@ -1,23 +1,26 @@ # frozen_string_literal: true -class PaymentServices::ExPay - class Invoice < ::PaymentServices::Base::FiatInvoice - INITIAL_PROVIDER_STATE = 'ACCEPTED' - SUCCESS_PROVIDER_STATE = 'SUCCESS' - FAILED_PROVIDER_STATE = 'ERROR' - self.table_name = 'ex_pay_invoices' +module PaymentServices + class ExPay + class Invoice < ::PaymentServices::Base::FiatInvoice + INITIAL_PROVIDER_STATE = 'ACCEPTED' + SUCCESS_PROVIDER_STATE = 'SUCCESS' + FAILED_PROVIDER_STATE = 'ERROR' - monetize :amount_cents, as: :amount + self.table_name = 'ex_pay_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/ex_pay/invoicer.rb b/lib/payment_services/ex_pay/invoicer.rb index debe0c41..25d38fec 100644 --- a/lib/payment_services/ex_pay/invoicer.rb +++ b/lib/payment_services/ex_pay/invoicer.rb @@ -3,71 +3,74 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::ExPay - class Invoicer < ::PaymentServices::Base::Invoicer - MERCHANT_ID = '1' - CURRENCY_TO_PROVIDER_TOKEN = { - 'RUB' => 'CARDRUBP2P', - 'UZS' => 'UZSP2P', - 'AZN' => 'AZNP2P' - }.freeze - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_p2p_params) - raise response['description'] unless response['status'] == Invoice::INITIAL_PROVIDER_STATE +module PaymentServices + class ExPay + class Invoicer < ::PaymentServices::Base::Invoicer + MERCHANT_ID = '1' + CURRENCY_TO_PROVIDER_TOKEN = { + 'RUB' => 'CARDRUBP2P', + 'UZS' => 'UZSP2P', + 'AZN' => 'AZNP2P' + }.freeze - invoice.update!( - deposit_id: response['tracker_id'], - pay_url: response['alter_refer'] - ) - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_p2p_params) + raise response['description'] unless response['status'] == Invoice::INITIAL_PROVIDER_STATE - def pay_invoice_url - invoice.reload.pay_url if invoice - end + invoice.update!( + deposit_id: response['tracker_id'], + pay_url: response['alter_refer'] + ) + end - def async_invoice_state_updater? - true - end + def pay_invoice_url + invoice.reload.pay_url if invoice + end - def update_invoice_state! - transaction = client.transaction(tracker_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['status']) if transaction - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(tracker_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['status']) if transaction + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :income_payment_system, :income_currency, to: :order - delegate :callback_url, to: :income_payment_system + private - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + delegate :income_payment_system, :income_currency, to: :order + delegate :callback_url, to: :income_payment_system - def invoice_p2p_params - { - refer_type: 'p2p_payform', - token: CURRENCY_TO_PROVIDER_TOKEN[income_currency.to_s], - sub_token: provider_bank, - amount: order.income_money.to_f, - client_transaction_id: order.public_id.to_s, - client_merchant_id: MERCHANT_ID, - fingerprint: "#{Rails.env}_user_id_#{order.user_id}", - transaction_description: order.public_id.to_s - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def provider_bank - @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank - end + def invoice_p2p_params + { + refer_type: 'p2p_payform', + token: CURRENCY_TO_PROVIDER_TOKEN[income_currency.to_s], + sub_token: provider_bank, + amount: order.income_money.to_f, + client_transaction_id: order.public_id.to_s, + client_merchant_id: MERCHANT_ID, + fingerprint: "#{Rails.env}_user_id_#{order.user_id}", + transaction_description: order.public_id.to_s + } + end + + def provider_bank + @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/ex_pay/payout.rb b/lib/payment_services/ex_pay/payout.rb index 7a36e41c..2b3d13b5 100644 --- a/lib/payment_services/ex_pay/payout.rb +++ b/lib/payment_services/ex_pay/payout.rb @@ -1,19 +1,22 @@ # frozen_string_literal: true -class PaymentServices::ExPay - class Payout < ::PaymentServices::Base::FiatPayout - self.table_name = 'ex_pay_payouts' - monetize :amount_cents, as: :amount +module PaymentServices + class ExPay + class Payout < ::PaymentServices::Base::FiatPayout + self.table_name = 'ex_pay_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == Invoice::SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == Invoice::SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == Invoice::FAILED_PROVIDER_STATE + def provider_failed? + provider_state == Invoice::FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/ex_pay/payout_adapter.rb b/lib/payment_services/ex_pay/payout_adapter.rb index 298cd0e3..38cbc8f6 100644 --- a/lib/payment_services/ex_pay/payout_adapter.rb +++ b/lib/payment_services/ex_pay/payout_adapter.rb @@ -3,52 +3,55 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::ExPay - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - PAYOUT_PROVIDER_TOKEN = 'CARDRUBP2P' - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? - - transaction = client.transaction(tracker_id: payout.withdrawal_id) - payout.update_state_by_provider(transaction['status']) if transaction - transaction - end - - private - - attr_reader :payout - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise "Can't create payout: #{response['description']}" unless response['status'] == Invoice::INITIAL_PROVIDER_STATE - - payout.pay!(withdrawal_id: response['tracker_id']) - end - - def payout_params - order = OrderPayout.find(payout.order_payout_id).order - { - amount: payout.amount.to_i, - call_back_url: order.outcome_payment_system.callback_url, - client_transaction_id: "#{order.public_id}-#{payout.order_payout_id}", - receiver: payout.destination_account, - token: PAYOUT_PROVIDER_TOKEN - } - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class ExPay + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + PAYOUT_PROVIDER_TOKEN = 'CARDRUBP2P' + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? + + transaction = client.transaction(tracker_id: payout.withdrawal_id) + payout.update_state_by_provider(transaction['status']) if transaction + transaction + end + + private + + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise "Can't create payout: #{response['description']}" unless response['status'] == Invoice::INITIAL_PROVIDER_STATE + + payout.pay!(withdrawal_id: response['tracker_id']) + end + + def payout_params + order = OrderPayout.find(payout.order_payout_id).order + { + amount: payout.amount.to_i, + call_back_url: order.outcome_payment_system.callback_url, + client_transaction_id: "#{order.public_id}-#{payout.order_payout_id}", + receiver: payout.destination_account, + token: PAYOUT_PROVIDER_TOKEN + } + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/exmo/client.rb b/lib/payment_services/exmo/client.rb index 28a37884..ed41a843 100644 --- a/lib/payment_services/exmo/client.rb +++ b/lib/payment_services/exmo/client.rb @@ -1,66 +1,69 @@ # frozen_string_literal: true -class PaymentServices::Exmo - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.exmo.me/v1.1' - def initialize(public_key:, secret_key:) - @public_key = public_key - @secret_key = secret_key - end +module PaymentServices + class Exmo + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.exmo.me/v1.1' - def create_payout(params:) - body = URI.encode_www_form(params.merge(nonce: nonce)) - safely_parse http_request( - url: "#{API_URL}/withdraw_crypt", - method: :POST, - body: body, - headers: build_headers(build_signature(body)) - ) - end + def initialize(public_key:, secret_key:) + @public_key = public_key + @secret_key = secret_key + end - def wallet_operations(currency:, type:) - body = URI.encode_www_form({ - currency: currency, - type: type, - nonce: nonce - }) - safely_parse http_request( - url: "#{API_URL}/wallet_operations", - method: :POST, - body: body, - headers: build_headers(build_signature(body)) - ) - end + def create_payout(params:) + body = URI.encode_www_form(params.merge(nonce: nonce)) + safely_parse http_request( + url: "#{API_URL}/withdraw_crypt", + method: :POST, + body: body, + headers: build_headers(build_signature(body)) + ) + end - def transaction_id(task_id:) - body = URI.encode_www_form({ task_id: task_id, nonce: nonce }) - safely_parse http_request( - url: "#{API_URL}/withdraw_get_txid", - method: :POST, - body: body, - headers: build_headers(build_signature(body)) - ) - end + def wallet_operations(currency:, type:) + body = URI.encode_www_form({ + currency: currency, + type: type, + nonce: nonce + }) + safely_parse http_request( + url: "#{API_URL}/wallet_operations", + method: :POST, + body: body, + headers: build_headers(build_signature(body)) + ) + end - private + def transaction_id(task_id:) + body = URI.encode_www_form({ task_id: task_id, nonce: nonce }) + safely_parse http_request( + url: "#{API_URL}/withdraw_get_txid", + method: :POST, + body: body, + headers: build_headers(build_signature(body)) + ) + end - attr_reader :public_key, :secret_key + private - def build_headers(signature) - { - 'Content-Type' => 'application/x-www-form-urlencoded', - 'Key' => public_key, - 'Sign' => signature - } - end + attr_reader :public_key, :secret_key - def nonce - Time.now.strftime("%s%6N") - end + def build_headers(signature) + { + 'Content-Type' => 'application/x-www-form-urlencoded', + 'Key' => public_key, + 'Sign' => signature + } + end + + def nonce + Time.now.strftime("%s%6N") + end - def build_signature(request_body) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), secret_key, request_body) + def build_signature(request_body) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha512'), secret_key, request_body) + end end end end diff --git a/lib/payment_services/exmo/invoice.rb b/lib/payment_services/exmo/invoice.rb index 3d17ab47..ec3fa30c 100644 --- a/lib/payment_services/exmo/invoice.rb +++ b/lib/payment_services/exmo/invoice.rb @@ -1,51 +1,54 @@ # frozen_string_literal: true -class PaymentServices::Exmo - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'exmo_invoices' +module PaymentServices + class Exmo + class Invoice < ApplicationRecord + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'exmo_invoices' - monetize :amount_cents, as: :amount + scope :ordered, -> { order(id: :desc) } - validates :amount_cents, :order_public_id, :state, presence: true + monetize :amount_cents, as: :amount - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - pay! if success? - cancel! if failed? - end + pay! if success? + cancel! if failed? + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - private + private - def success? - transaction_id.present? - end + def success? + transaction_id.present? + end - def failed? - provider_state == 'Cancelled' || provider_state == 'Error' + def failed? + provider_state == 'Cancelled' || provider_state == 'Error' + end end end end diff --git a/lib/payment_services/exmo/invoicer.rb b/lib/payment_services/exmo/invoicer.rb index f93e9668..abd6db69 100644 --- a/lib/payment_services/exmo/invoicer.rb +++ b/lib/payment_services/exmo/invoicer.rb @@ -3,62 +3,65 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Exmo - class Invoicer < ::PaymentServices::Base::Invoicer - TRANSACTION_TIME_THRESHOLD = 30.minutes - WalletOperationsRequestFailed = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - end +module PaymentServices + class Exmo + class Invoicer < ::PaymentServices::Base::Invoicer + TRANSACTION_TIME_THRESHOLD = 30.minutes + WalletOperationsRequestFailed = Class.new StandardError - def async_invoice_state_updater? - true - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + end - def update_invoice_state! - response = client.wallet_operations(currency: invoice.amount_currency, type: 'deposit') - raise WalletOperationsRequestFailed, "Can't get wallet operations" unless response['items'] + def async_invoice_state_updater? + true + end - transaction = find_transaction(transactions: response['items']) - return if transaction.nil? + def update_invoice_state! + response = client.wallet_operations(currency: invoice.amount_currency, type: 'deposit') + raise WalletOperationsRequestFailed, "Can't get wallet operations" unless response['items'] - invoice.update!( - transaction_created_at: DateTime.strptime(transaction['created'].to_s,'%s').utc, - transaction_id: transaction.dig('extra', 'txid') - ) - invoice.update_state_by_provider(transaction['status']) - end + transaction = find_transaction(transactions: response['items']) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update!( + transaction_created_at: DateTime.strptime(transaction['created'].to_s,'%s').utc, + transaction_id: transaction.dig('extra', 'txid') + ) + invoice.update_state_by_provider(transaction['status']) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def find_transaction(transactions:) - transactions.find { |transaction| matches_amount_and_timing?(transaction) } - end + private - def matches_amount_and_timing?(transaction) - transaction['amount'].to_d == invoice.amount.to_d && match_time_interval?(transaction) - end + def find_transaction(transactions:) + transactions.find { |transaction| matches_amount_and_timing?(transaction) } + end - def match_time_interval?(transaction) - transaction_created_at_utc = DateTime.strptime(transaction['created'].to_s,'%s').utc - invoice_created_at_utc = invoice.created_at.utc + def matches_amount_and_timing?(transaction) + transaction['amount'].to_d == invoice.amount.to_d && match_time_interval?(transaction) + end - invoice_created_at_utc < transaction_created_at_utc && created_in_valid_interval?(transaction_created_at_utc, invoice_created_at_utc) - end + def match_time_interval?(transaction) + transaction_created_at_utc = DateTime.strptime(transaction['created'].to_s,'%s').utc + invoice_created_at_utc = invoice.created_at.utc - def created_in_valid_interval?(transaction_time, invoice_time) - interval = (transaction_time - invoice_time) - interval_in_minutes = (interval / 1.minute).round.minutes - interval_in_minutes < TRANSACTION_TIME_THRESHOLD - end + invoice_created_at_utc < transaction_created_at_utc && created_in_valid_interval?(transaction_created_at_utc, invoice_created_at_utc) + end + + def created_in_valid_interval?(transaction_time, invoice_time) + interval = (transaction_time - invoice_time) + interval_in_minutes = (interval / 1.minute).round.minutes + interval_in_minutes < TRANSACTION_TIME_THRESHOLD + end - def client - @client ||= Client.new(public_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(public_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/exmo/payout.rb b/lib/payment_services/exmo/payout.rb index b2c801c3..0c94b063 100644 --- a/lib/payment_services/exmo/payout.rb +++ b/lib/payment_services/exmo/payout.rb @@ -1,57 +1,60 @@ # frozen_string_literal: true -class PaymentServices::Exmo - class Payout < ApplicationRecord - include Workflow - self.table_name = 'exmo_payouts' +module PaymentServices + class Exmo + class Payout < ApplicationRecord + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'exmo_payouts' - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true + scope :ordered, -> { order(id: :desc) } - alias_attribute :txid, :transaction_id + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true - delegate :order, to: :order_payout - delegate :outcome_payment_system, to: :order - delegate :token_network, to: :outcome_payment_system + alias_attribute :txid, :transaction_id - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed + delegate :order, to: :order_payout + delegate :outcome_payment_system, to: :order + delegate :token_network, to: :outcome_payment_system + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(task_id:) - update(task_id: task_id) - end + def pay(task_id:) + update(task_id: task_id) + end - def order_fio - order_payout.order.outcome_fio.presence || order_payout.order.outcome_unk - end + def order_fio + order_payout.order.outcome_fio.presence || order_payout.order.outcome_unk + end - def update_payout_details!(transaction:) - update!( - provider_state: transaction.provider_state, - transaction_id: transaction.id - ) + def update_payout_details!(transaction:) + update!( + provider_state: transaction.provider_state, + transaction_id: transaction.id + ) - confirm! if transaction.successful? - fail! if transaction.failed? - end + confirm! if transaction.successful? + fail! if transaction.failed? + end - private + private - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end end end end diff --git a/lib/payment_services/exmo/payout_adapter.rb b/lib/payment_services/exmo/payout_adapter.rb index c776708d..f654fdf0 100644 --- a/lib/payment_services/exmo/payout_adapter.rb +++ b/lib/payment_services/exmo/payout_adapter.rb @@ -4,81 +4,84 @@ require_relative 'client' require_relative 'transaction' -class PaymentServices::Exmo - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - INVOICED_CURRENCIES = %w[xrp xem xlm] - Error = Class.new StandardError - PayoutCreateRequestFailed = Class.new Error - WalletOperationsRequestFailed = Class.new Error - - delegate :outcome_transaction_fee_amount, to: :payment_system - delegate :neo?, :usdt?, to: :currency, prefix: true - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class Exmo + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + INVOICED_CURRENCIES = %w[xrp xem xlm] + Error = Class.new StandardError + PayoutCreateRequestFailed = Class.new Error + WalletOperationsRequestFailed = Class.new Error + + delegate :outcome_transaction_fee_amount, to: :payment_system + delegate :neo?, :usdt?, to: :currency, prefix: true - response = client.wallet_operations(currency: currency.upcase, type: 'withdrawal') - raise WalletOperationsRequestFailed, "Can't get wallet operations" unless response['items'] + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - raw_transaction = find_transaction_of(payout: payout, transactions: response['items']) - return if raw_transaction.nil? + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - transaction = Transaction.build_from(raw_transaction: raw_transaction) - transaction.id = client.transaction_id(task_id: payout.task_id)['txid'] - payout.update_payout_details!(transaction: transaction) - transaction - end + response = client.wallet_operations(currency: currency.upcase, type: 'withdrawal') + raise WalletOperationsRequestFailed, "Can't get wallet operations" unless response['items'] - private - - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - payout_params = { - amount: amount.to_d + (outcome_transaction_fee_amount || 0), - currency: currency.upcase, - address: destination_account - } - if invoice_required? - payout_params[:invoice] = payout.order_fio.present? ? payout.order_fio : '1' + raw_transaction = find_transaction_of(payout: payout, transactions: response['items']) + return if raw_transaction.nil? + + transaction = Transaction.build_from(raw_transaction: raw_transaction) + transaction.id = client.transaction_id(task_id: payout.task_id)['txid'] + payout.update_payout_details!(transaction: transaction) + transaction end - payout_params[:amount] = payout_params[:amount].to_i if currency_neo? - payout_params[:transport] = payout.token_network.upcase if currency_usdt? - response = client.create_payout(params: payout_params) - raise PayoutCreateRequestFailed, "Can't create payout: #{response['error']}" unless response['result'] - payout.pay!(task_id: response['task_id'].to_i) - end + private + + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + payout_params = { + amount: amount.to_d + (outcome_transaction_fee_amount || 0), + currency: currency.upcase, + address: destination_account + } + if invoice_required? + payout_params[:invoice] = payout.order_fio.present? ? payout.order_fio : '1' + end + payout_params[:amount] = payout_params[:amount].to_i if currency_neo? + payout_params[:transport] = payout.token_network.upcase if currency_usdt? + response = client.create_payout(params: payout_params) + raise PayoutCreateRequestFailed, "Can't create payout: #{response['error']}" unless response['result'] - def find_transaction_of(payout:, transactions:) - transactions.find do |transaction| - transaction['order_id'] == payout.task_id && (payout.amount.to_d + (outcome_transaction_fee_amount || 0)) == transaction['amount'].to_d + payout.pay!(task_id: response['task_id'].to_i) end - end - def client - @client ||= begin - Client.new(public_key: api_key, secret_key: api_secret) + def find_transaction_of(payout:, transactions:) + transactions.find do |transaction| + transaction['order_id'] == payout.task_id && (payout.amount.to_d + (outcome_transaction_fee_amount || 0)) == transaction['amount'].to_d + end end - end - def invoice_required? - INVOICED_CURRENCIES.include?(currency) - end + def client + @client ||= begin + Client.new(public_key: api_key, secret_key: api_secret) + end + end + + def invoice_required? + INVOICED_CURRENCIES.include?(currency) + end - def currency - @currency ||= begin - cur = wallet.currency.to_s.downcase - cur = 'dash' if cur == 'dsh' - cur.inquiry + def currency + @currency ||= begin + cur = wallet.currency.to_s.downcase + cur = 'dash' if cur == 'dsh' + cur.inquiry + end end end end diff --git a/lib/payment_services/exmo/transaction.rb b/lib/payment_services/exmo/transaction.rb index ffd27db6..087cd248 100644 --- a/lib/payment_services/exmo/transaction.rb +++ b/lib/payment_services/exmo/transaction.rb @@ -1,34 +1,37 @@ # frozen_string_literal: true -class PaymentServices::Exmo - class Transaction - include Virtus.model - - SUCCESSFULL_PROVIDER_STATE = 'Paid' - FAILED_PROVIDER_STATES = %w(Cancelled Error) - - attribute :id, String - attribute :provider_state, Integer - attribute :source, String - - def self.build_from(raw_transaction:) - new( - id: raw_transaction['extra']['txid'], - provider_state: raw_transaction['status'], - source: raw_transaction - ) - end - def to_s - source.to_s - end +module PaymentServices + class Exmo + class Transaction + include Virtus.model - def successful? - provider_state == SUCCESSFULL_PROVIDER_STATE - end + SUCCESSFULL_PROVIDER_STATE = 'Paid' + FAILED_PROVIDER_STATES = %w(Cancelled Error) + + attribute :id, String + attribute :provider_state, Integer + attribute :source, String + + def self.build_from(raw_transaction:) + new( + id: raw_transaction['extra']['txid'], + provider_state: raw_transaction['status'], + source: raw_transaction + ) + end + + def to_s + source.to_s + end + + def successful? + provider_state == SUCCESSFULL_PROVIDER_STATE + end - def failed? - FAILED_PROVIDER_STATES.include?(provider_state) + def failed? + FAILED_PROVIDER_STATES.include?(provider_state) + end end end end diff --git a/lib/payment_services/ff/client.rb b/lib/payment_services/ff/client.rb index c30ef7af..fa3d1f19 100644 --- a/lib/payment_services/ff/client.rb +++ b/lib/payment_services/ff/client.rb @@ -1,56 +1,59 @@ # frozen_string_literal: true -class PaymentServices::Ff - class Client < ::PaymentServices::Base::Client - API_URL = 'https://ff.io/api/v2' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/create", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end - - def transaction(params:) - safely_parse http_request( - url: "#{API_URL}/order", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end - - def ccies - safely_parse http_request( - url: "#{API_URL}/ccies", - method: :POST, - body: {}.to_json, - headers: build_headers(signature: build_signature({})) - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_headers(signature:) - { - 'Accept' => 'application/json', - 'X-API-KEY' => api_key, - 'X-API-SIGN' => signature, - 'Content-Type' => 'application/json; charset=UTF-8' - } - end - - def build_signature(params) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, params.to_json) +module PaymentServices + class Ff + class Client < ::PaymentServices::Base::Client + API_URL = 'https://ff.io/api/v2' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/create", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end + + def transaction(params:) + safely_parse http_request( + url: "#{API_URL}/order", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end + + def ccies + safely_parse http_request( + url: "#{API_URL}/ccies", + method: :POST, + body: {}.to_json, + headers: build_headers(signature: build_signature({})) + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'Accept' => 'application/json', + 'X-API-KEY' => api_key, + 'X-API-SIGN' => signature, + 'Content-Type' => 'application/json; charset=UTF-8' + } + end + + def build_signature(params) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, params.to_json) + end end end end diff --git a/lib/payment_services/ff/invoice.rb b/lib/payment_services/ff/invoice.rb index 2a6587ff..6a84024f 100644 --- a/lib/payment_services/ff/invoice.rb +++ b/lib/payment_services/ff/invoice.rb @@ -1,24 +1,27 @@ # frozen_string_literal: true -class PaymentServices::Ff - class Invoice < ::PaymentServices::Base::CryptoInvoice - self.table_name = 'ff_invoices' - monetize :amount_cents, as: :amount +module PaymentServices + class Ff + class Invoice < ::PaymentServices::Base::CryptoInvoice + self.table_name = 'ff_invoices' - def update_state_by_transaction(transaction) - bind_transaction! if pending? - update!( - transaction_id: transaction.id, - provider_state: transaction.status - ) + monetize :amount_cents, as: :amount - pay!(payload: transaction) if transaction.income_succeed? - cancel! if transaction.failed? - end + def update_state_by_transaction(transaction) + bind_transaction! if pending? + update!( + transaction_id: transaction.id, + provider_state: transaction.status + ) + + pay!(payload: transaction) if transaction.income_succeed? + cancel! if transaction.failed? + end - def transaction_created_at - nil + def transaction_created_at + nil + end end end end diff --git a/lib/payment_services/ff/invoicer.rb b/lib/payment_services/ff/invoicer.rb index dfd7a6d1..762d56fc 100644 --- a/lib/payment_services/ff/invoicer.rb +++ b/lib/payment_services/ff/invoicer.rb @@ -4,70 +4,73 @@ require_relative 'invoice' require_relative 'transaction' -class PaymentServices::Ff - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - SUCCESS_REQUEST_STATUS_CODE = 0 - FEE_IN_PERCENTS = 0.5 - REF_CODE = 'jznep39b' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise Error, "Can't create invoice: #{response['msg']}" if response['code'] != SUCCESS_REQUEST_STATUS_CODE +module PaymentServices + class Ff + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + SUCCESS_REQUEST_STATUS_CODE = 0 + FEE_IN_PERCENTS = 0.5 + REF_CODE = 'jznep39b' - invoice.update!(deposit_id: response.dig('data', 'id'), access_token: response.dig('data', 'token')) - PaymentServices::Base::Wallet.new( - address: response['data']['from']['address'], - name: nil, - memo: response['data']['from']['tag'].presence - ) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise Error, "Can't create invoice: #{response['msg']}" if response['code'] != SUCCESS_REQUEST_STATUS_CODE - def create_invoice(money) - invoice - end + invoice.update!(deposit_id: response.dig('data', 'id'), access_token: response.dig('data', 'token')) + PaymentServices::Base::Wallet.new( + address: response['data']['from']['address'], + name: nil, + memo: response['data']['from']['tag'].presence + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - raw_transaction = client.transaction(params: { id: invoice.deposit_id, token: invoice.access_token }) - transaction = Transaction.build_from(raw_transaction['data']) - invoice.update_state_by_transaction(transaction) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + raw_transaction = client.transaction(params: { id: invoice.deposit_id, token: invoice.access_token }) + transaction = Transaction.build_from(raw_transaction['data']) + invoice.update_state_by_transaction(transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_params - type = order.exchange_rate_flexible_rate? && order.flexible_rate? ? 'float' : 'fixed' - from = order.income_currency.to_s - from = 'BSC' if from == 'BNB' - params = { - type: type, - fromCcy: from, - toCcy: order.outcome_currency.to_s, - direction: 'from', - amount: invoice.amount.to_f, - toAddress: order.outcome_account, - refcode: REF_CODE, - afftax: FEE_IN_PERCENTS - } - params[:tag] = order.outcome_unk if order.outcome_unk.present? - params - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end + + def invoice_params + type = order.exchange_rate_flexible_rate? && order.flexible_rate? ? 'float' : 'fixed' + from = order.income_currency.to_s + from = 'BSC' if from == 'BNB' + params = { + type: type, + fromCcy: from, + toCcy: order.outcome_currency.to_s, + direction: 'from', + amount: invoice.amount.to_f, + toAddress: order.outcome_account, + refcode: REF_CODE, + afftax: FEE_IN_PERCENTS + } + params[:tag] = order.outcome_unk if order.outcome_unk.present? + params + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/ff/payout.rb b/lib/payment_services/ff/payout.rb index e6a45376..33051669 100644 --- a/lib/payment_services/ff/payout.rb +++ b/lib/payment_services/ff/payout.rb @@ -1,23 +1,26 @@ # frozen_string_literal: true -class PaymentServices::Ff - class Payout < ::PaymentServices::Base::CryptoPayout - self.table_name = 'ff_payouts' - monetize :amount_cents, as: :amount +module PaymentServices + class Ff + class Payout < ::PaymentServices::Base::CryptoPayout + self.table_name = 'ff_payouts' - def txid - transaction_id - end + monetize :amount_cents, as: :amount + + def txid + transaction_id + end - def update_state_by_provider!(transaction) - update!( - transaction_id: transaction.id, - provider_state: transaction.status - ) + def update_state_by_provider!(transaction) + update!( + transaction_id: transaction.id, + provider_state: transaction.status + ) - confirm! if transaction.outcome_succeed? - fail! if transaction.failed? + confirm! if transaction.outcome_succeed? + fail! if transaction.failed? + end end end end diff --git a/lib/payment_services/ff/payout_adapter.rb b/lib/payment_services/ff/payout_adapter.rb index ba0569ca..807758d8 100644 --- a/lib/payment_services/ff/payout_adapter.rb +++ b/lib/payment_services/ff/payout_adapter.rb @@ -5,46 +5,49 @@ require_relative 'invoice' require_relative 'transaction' -class PaymentServices::Ff - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? +module PaymentServices + class Ff + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - raw_transaction = client.transaction(params: { id: payout.withdrawal_id, token: payout.access_token }) - transaction = Transaction.build_from(raw_transaction['data'], direction: :to) - payout.update_state_by_provider!(transaction) + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? - transaction - end + raw_transaction = client.transaction(params: { id: payout.withdrawal_id, token: payout.access_token }) + transaction = Transaction.build_from(raw_transaction['data'], direction: :to) + payout.update_state_by_provider!(transaction) - def payout - @payout ||= Payout.find_by(id: payout_id) - end + transaction + end - private + def payout + @payout ||= Payout.find_by(id: payout_id) + end - attr_accessor :payout_id + private - def make_payout(amount:, destination_account:, order_payout_id:) - @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id + attr_accessor :payout_id - invoice = Invoice.find_by!(order_public_id: OrderPayout.find(payout.order_payout_id).order.public_id) + def make_payout(amount:, destination_account:, order_payout_id:) + @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id - payout.pay!(withdrawal_id: invoice.deposit_id) - payout.update!(access_token: invoice.access_token) - end + invoice = Invoice.find_by!(order_public_id: OrderPayout.find(payout.order_payout_id).order.public_id) + + payout.pay!(withdrawal_id: invoice.deposit_id) + payout.update!(access_token: invoice.access_token) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/ff/transaction.rb b/lib/payment_services/ff/transaction.rb index 6e75f843..867d98ec 100644 --- a/lib/payment_services/ff/transaction.rb +++ b/lib/payment_services/ff/transaction.rb @@ -1,40 +1,43 @@ # frozen_string_literal: true -class PaymentServices::Ff - class Transaction - SUCCESS_INCOME_PROVIDER_STATE = 'EXCHANGE' - SUCCESS_OUTCOME_PROVIDER_STATE = 'DONE' - FAILED_PROVIDER_STATE = 'EXPIRED' - DELAY = 10.minutes - - include Virtus.model - - attribute :id, String - attribute :status, String - attribute :source, Hash - - def self.build_from(raw_transaction, direction: :from) - new( - status: raw_transaction['status'], - id: raw_transaction[direction.to_s]['tx']['id'], - source: raw_transaction - ) - end - - def to_s - source.to_s - end - - def income_succeed? - status == SUCCESS_INCOME_PROVIDER_STATE || status == SUCCESS_OUTCOME_PROVIDER_STATE - end - - def outcome_succeed? - status == SUCCESS_OUTCOME_PROVIDER_STATE && source['time']['finish'].present? && Time.at(source['time']['finish']) + DELAY < Time.current - end - def failed? - status == FAILED_PROVIDER_STATE +module PaymentServices + class Ff + class Transaction + SUCCESS_INCOME_PROVIDER_STATE = 'EXCHANGE' + SUCCESS_OUTCOME_PROVIDER_STATE = 'DONE' + FAILED_PROVIDER_STATE = 'EXPIRED' + DELAY = 10.minutes + + include Virtus.model + + attribute :id, String + attribute :status, String + attribute :source, Hash + + def self.build_from(raw_transaction, direction: :from) + new( + status: raw_transaction['status'], + id: raw_transaction[direction.to_s]['tx']['id'], + source: raw_transaction + ) + end + + def to_s + source.to_s + end + + def income_succeed? + status == SUCCESS_INCOME_PROVIDER_STATE || status == SUCCESS_OUTCOME_PROVIDER_STATE + end + + def outcome_succeed? + status == SUCCESS_OUTCOME_PROVIDER_STATE && source['time']['finish'].present? && Time.at(source['time']['finish']) + DELAY < Time.current + end + + def failed? + status == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/fire_kassa/client.rb b/lib/payment_services/fire_kassa/client.rb index 81fbc204..8f5b77af 100644 --- a/lib/payment_services/fire_kassa/client.rb +++ b/lib/payment_services/fire_kassa/client.rb @@ -1,48 +1,51 @@ # frozen_string_literal: true -class PaymentServices::FireKassa - class Client < ::PaymentServices::Base::Client - API_URL = 'https://admin.vanilapay.com/api/v2' - def initialize(api_key:) - @api_key = api_key - end - - def create_card_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/deposit/card", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end - - def create_sbp_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/deposit/sbp-a", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end - - def transaction(transaction_id:) - safely_parse http_request( - url: "#{API_URL}/transactions/#{transaction_id}", - method: :GET, - headers: build_headers - ) - end - - private - - attr_reader :api_key - - def build_headers - { - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer #{api_key}" - } +module PaymentServices + class FireKassa + class Client < ::PaymentServices::Base::Client + API_URL = 'https://admin.vanilapay.com/api/v2' + + def initialize(api_key:) + @api_key = api_key + end + + def create_card_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/deposit/card", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end + + def create_sbp_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/deposit/sbp-a", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end + + def transaction(transaction_id:) + safely_parse http_request( + url: "#{API_URL}/transactions/#{transaction_id}", + method: :GET, + headers: build_headers + ) + end + + private + + attr_reader :api_key + + def build_headers + { + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{api_key}" + } + end end end end diff --git a/lib/payment_services/fire_kassa/invoice.rb b/lib/payment_services/fire_kassa/invoice.rb index 4be6ffa4..bb61fb43 100644 --- a/lib/payment_services/fire_kassa/invoice.rb +++ b/lib/payment_services/fire_kassa/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::FireKassa - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATES = %w(paid overpaid) - FAILED_PROVIDER_STATE = 'expired' - self.table_name = 'fire_kassa_invoices' +module PaymentServices + class FireKassa + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATES = %w(paid overpaid) + FAILED_PROVIDER_STATE = 'expired' - monetize :amount_cents, as: :amount + self.table_name = 'fire_kassa_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state.in? SUCCESS_PROVIDER_STATES - end + private + + def provider_succeed? + provider_state.in? SUCCESS_PROVIDER_STATES + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/fire_kassa/invoicer.rb b/lib/payment_services/fire_kassa/invoicer.rb index db01a39c..6c8b60d5 100644 --- a/lib/payment_services/fire_kassa/invoicer.rb +++ b/lib/payment_services/fire_kassa/invoicer.rb @@ -3,79 +3,82 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::FireKassa - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - DEFAULT_CARD = 'sber' - - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = sbp? ? client.create_sbp_invoice(params: invoice_params) : client.create_card_invoice(params: invoice_params) - raise Error, "Can't create invoice: #{response['message']}" if response['message'] - - invoice.update!(deposit_id: response['id']) - PaymentServices::Base::Wallet.new( - address: response['card_number'] || format_phone_number(response['account']), - name: [response['first_name'].capitalize, response['last_name'].capitalize].join(' '), - memo: response['bank'].capitalize - ) - end - def create_invoice(money) - invoice - end +module PaymentServices + class FireKassa + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + DEFAULT_CARD = 'sber' - def async_invoice_state_updater? - true - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = sbp? ? client.create_sbp_invoice(params: invoice_params) : client.create_card_invoice(params: invoice_params) + raise Error, "Can't create invoice: #{response['message']}" if response['message'] - def update_invoice_state! - transaction = client.transaction(transaction_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['status']) - end + invoice.update!(deposit_id: response['id']) + PaymentServices::Base::Wallet.new( + address: response['card_number'] || format_phone_number(response['account']), + name: [response['first_name'].capitalize, response['last_name'].capitalize].join(' '), + memo: response['bank'].capitalize + ) + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def create_invoice(money) + invoice + end - private + def async_invoice_state_updater? + true + end - delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver + def update_invoice_state! + transaction = client.transaction(transaction_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['status']) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def invoice_params - params = { - account: order.income_account, - order_id: order.public_id.to_s, - site_account: DEFAULT_CARD, - amount: invoice.amount.to_f.to_s, - comment: "Order ##{order.public_id.to_s}", - ext_txn: order.public_id.to_s, - ext_date: order.created_at.iso8601 - } - params[:ext_last_name] = order.user.aml_client.surname if order&.user&.aml_client&.surname.present? - params[:ext_first_name] = order.user.aml_client.first_name if order&.user&.aml_client&.first_name.present? - params[:ext_email] = order.user_email if order&.user&.email.present? - params[:ext_ip] = order.remote_ip if order.remote_ip.present? - params[:ext_user_agent] = order.user.user_agent if order&.user&.user_agent.present? - params[:ext_photo] = CardVerification.find_by(order_public_id: order.public_id).image.url if CardVerification.find_by(order_public_id: order.public_id)&.image&.url.present? - params[:bank_id] = sbp_bank if sbp? - params - end + private - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver - def client - @client ||= Client.new(api_key: api_key) - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end + + def invoice_params + params = { + account: order.income_account, + order_id: order.public_id.to_s, + site_account: DEFAULT_CARD, + amount: invoice.amount.to_f.to_s, + comment: "Order ##{order.public_id.to_s}", + ext_txn: order.public_id.to_s, + ext_date: order.created_at.iso8601 + } + params[:ext_last_name] = order.user.aml_client.surname if order&.user&.aml_client&.surname.present? + params[:ext_first_name] = order.user.aml_client.first_name if order&.user&.aml_client&.first_name.present? + params[:ext_email] = order.user_email if order&.user&.email.present? + params[:ext_ip] = order.remote_ip if order.remote_ip.present? + params[:ext_user_agent] = order.user.user_agent if order&.user&.user_agent.present? + params[:ext_photo] = CardVerification.find_by(order_public_id: order.public_id).image.url if CardVerification.find_by(order_public_id: order.public_id)&.image&.url.present? + params[:bank_id] = sbp_bank if sbp? + params + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end + + def client + @client ||= Client.new(api_key: api_key) + end - def format_phone_number(account) - "+7 (#{account[0..2]}) #{account[3..5]}-#{account[6..7]}-#{account[8..9]}" + def format_phone_number(account) + "+7 (#{account[0..2]}) #{account[3..5]}-#{account[6..7]}-#{account[8..9]}" + end end end end diff --git a/lib/payment_services/just_pays/client.rb b/lib/payment_services/just_pays/client.rb index 22c55d82..da53d435 100644 --- a/lib/payment_services/just_pays/client.rb +++ b/lib/payment_services/just_pays/client.rb @@ -1,46 +1,49 @@ # frozen_string_literal: true -class PaymentServices::JustPays - class Client < ::PaymentServices::Base::Client - API_URL = 'https://merchant-api.just-pays.com/api' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payment_url", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end - - def transactions - safely_parse http_request( - url: "#{API_URL}/order_history", - method: :POST, - body: {}.to_json, - headers: build_headers(signature: build_signature) - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_signature(params = {}) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) - end - - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'X-API-Key' => api_key, - 'X-API-Sign' => signature - } +module PaymentServices + class JustPays + class Client < ::PaymentServices::Base::Client + API_URL = 'https://merchant-api.just-pays.com/api' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payment_url", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end + + def transactions + safely_parse http_request( + url: "#{API_URL}/order_history", + method: :POST, + body: {}.to_json, + headers: build_headers(signature: build_signature) + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_signature(params = {}) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) + end + + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'X-API-Key' => api_key, + 'X-API-Sign' => signature + } + end end end end diff --git a/lib/payment_services/just_pays/invoice.rb b/lib/payment_services/just_pays/invoice.rb index b3537e12..341d51cd 100644 --- a/lib/payment_services/just_pays/invoice.rb +++ b/lib/payment_services/just_pays/invoice.rb @@ -1,26 +1,29 @@ # frozen_string_literal: true -class PaymentServices::JustPays - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'OrderCompleted' - FAILED_PROVIDER_STATE = 'OrderCanceled' - self.table_name = 'just_pays_invoices' +module PaymentServices + class JustPays + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'OrderCompleted' + FAILED_PROVIDER_STATE = 'OrderCanceled' - monetize :amount_cents, as: :amount + self.table_name = 'just_pays_invoices' - def can_be_confirmed?(income_money:) - pending? && income_money == amount - end + monetize :amount_cents, as: :amount - private + def can_be_confirmed?(income_money:) + pending? && income_money == amount + end - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/just_pays/invoicer.rb b/lib/payment_services/just_pays/invoicer.rb index f77b4cb5..b133915e 100644 --- a/lib/payment_services/just_pays/invoicer.rb +++ b/lib/payment_services/just_pays/invoicer.rb @@ -3,55 +3,58 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::JustPays - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) - - raise Error, "Can't create invoice: #{response['error']}" if response['error'] - - invoice.update!( - deposit_id: response['internal_id'], - pay_url: response['payment_url'] - ) - end - - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end - - def async_invoice_state_updater? - false - end - - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end - - private - - def invoice_params - { - external_id: order.public_id.to_s, - external_meta: { - uid: order.user_id.to_s, - ip: order.remote_ip, - email: order.user_email - }, - currency_symbol: invoice.amount_currency.to_s, - region_code: invoice.amount_currency.to_s.first(2), - gross_amount: format('%.2f', invoice.amount.to_f), - success_url: order.success_redirect, - failed_url: order.failed_redirect, - callback_url: "#{routes_helper.public_public_callbacks_api_root_url}/v1/just_pays/receive_payment" - } - end - - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class JustPays + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) + + raise Error, "Can't create invoice: #{response['error']}" if response['error'] + + invoice.update!( + deposit_id: response['internal_id'], + pay_url: response['payment_url'] + ) + end + + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end + + def async_invoice_state_updater? + false + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + private + + def invoice_params + { + external_id: order.public_id.to_s, + external_meta: { + uid: order.user_id.to_s, + ip: order.remote_ip, + email: order.user_email + }, + currency_symbol: invoice.amount_currency.to_s, + region_code: invoice.amount_currency.to_s.first(2), + gross_amount: format('%.2f', invoice.amount.to_f), + success_url: order.success_redirect, + failed_url: order.failed_redirect, + callback_url: "#{routes_helper.public_public_callbacks_api_root_url}/v1/just_pays/receive_payment" + } + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/kuna/client.rb b/lib/payment_services/kuna/client.rb index 4448c4b3..62bb5a47 100644 --- a/lib/payment_services/kuna/client.rb +++ b/lib/payment_services/kuna/client.rb @@ -1,104 +1,107 @@ # frozen_string_literal: true -class PaymentServices::Kuna - class Client - include AutoLogger - TIMEOUT = 30 - API_URL = 'https://api.kuna.io' - - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - def create_deposit(params:) - safely_parse http_request( - url: API_URL + '/v3/auth/merchant/deposit', - method: :POST, - body: params - ) - end +module PaymentServices + class Kuna + class Client + include AutoLogger + TIMEOUT = 30 + API_URL = 'https://api.kuna.io' - def create_payout(params:) - safely_parse http_request( - url: API_URL + '/v3/auth/withdraw', - method: :POST, - body: params - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def payout_status(params:) - safely_parse http_request( - url: API_URL + '/v3/auth/withdraw/details', - method: :POST, - body: params - ) - end + def create_deposit(params:) + safely_parse http_request( + url: API_URL + '/v3/auth/merchant/deposit', + method: :POST, + body: params + ) + end - private + def create_payout(params:) + safely_parse http_request( + url: API_URL + '/v3/auth/withdraw', + method: :POST, + body: params + ) + end - attr_reader :api_key, :secret_key + def payout_status(params:) + safely_parse http_request( + url: API_URL + '/v3/auth/withdraw/details', + method: :POST, + body: params + ) + end - def http_request(url:, method:, body: nil) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + private - def build_request(uri:, method:, body: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers(uri.to_s, body)) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + attr_reader :api_key, :secret_key + + def http_request(url:, method:, body: nil) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def headers(url, params) - nonce = time_now_milliseconds + def build_request(uri:, method:, body: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers(uri.to_s, body)) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - { - 'Content-Type' => 'application/json', - 'kun-nonce' => nonce, - 'kun-apikey' => api_key, - 'kun-signature' => signature(url: url, params: params, nonce: nonce) - } - end + def headers(url, params) + nonce = time_now_milliseconds - def time_now_milliseconds - Time.now.strftime("%s%3N") - end + { + 'Content-Type' => 'application/json', + 'kun-nonce' => nonce, + 'kun-apikey' => api_key, + 'kun-signature' => signature(url: url, params: params, nonce: nonce) + } + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def time_now_milliseconds + Time.now.strftime("%s%3N") + end - def signature(url:, params:, nonce:) - url.slice!(API_URL) - sign_string = url + nonce + params.to_json + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end - OpenSSL::HMAC.hexdigest('SHA384', secret_key, sign_string) - end + def signature(url:, params:, nonce:) + url.slice!(API_URL) + sign_string = url + nonce + params.to_json + + OpenSSL::HMAC.hexdigest('SHA384', secret_key, sign_string) + end - def safely_parse(response) - res = JSON.parse(response.body) - logger.info "Response: #{res}" - res - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + def safely_parse(response) + res = JSON.parse(response.body) + logger.info "Response: #{res}" + res + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/kuna/invoice.rb b/lib/payment_services/kuna/invoice.rb index 604ca7ca..eaa3b94b 100644 --- a/lib/payment_services/kuna/invoice.rb +++ b/lib/payment_services/kuna/invoice.rb @@ -1,60 +1,63 @@ # frozen_string_literal: true -class PaymentServices::Kuna - class Invoice < ApplicationRecord - FEE_PERCENT = 0.5 - UAH_FEE_PERCENT = 1.0 - UAH_FEE_REGULAR = 5 - KOPECK_EPSILON = 1 - include Workflow +module PaymentServices + class Kuna + class Invoice < ApplicationRecord + FEE_PERCENT = 0.5 + UAH_FEE_PERCENT = 1.0 + UAH_FEE_REGULAR = 5 + KOPECK_EPSILON = 1 - self.table_name = 'kuna_invoices' + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'kuna_invoices' - monetize :amount_cents, as: :amount + scope :ordered, -> { order(id: :desc) } - validates :amount_cents, :order_public_id, :state, presence: true + monetize :amount_cents, as: :amount - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: deposit_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: deposit_id) + end end + state :cancelled end - state :cancelled - end - def can_be_confirmed?(income_money:) - pending? && amount_matches?(income_money) - end + def can_be_confirmed?(income_money:) + pending? && amount_matches?(income_money) + end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - private + private - def amount_matches?(income_amount) - (amount - income_amount - fee) <= Money.new(KOPECK_EPSILON, amount.currency) - end + def amount_matches?(income_amount) + (amount - income_amount - fee) <= Money.new(KOPECK_EPSILON, amount.currency) + end - def fee - if amount_currency == 'UAH' - amount * UAH_FEE_PERCENT / 100 + Money.from_amount(UAH_FEE_REGULAR, amount_currency) - else - amount * FEE_PERCENT / 100 + def fee + if amount_currency == 'UAH' + amount * UAH_FEE_PERCENT / 100 + Money.from_amount(UAH_FEE_REGULAR, amount_currency) + else + amount * FEE_PERCENT / 100 + end end end end diff --git a/lib/payment_services/kuna/invoicer.rb b/lib/payment_services/kuna/invoicer.rb index 2fbcdd0c..9a258aac 100644 --- a/lib/payment_services/kuna/invoicer.rb +++ b/lib/payment_services/kuna/invoicer.rb @@ -3,76 +3,79 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Kuna - class Invoicer < ::PaymentServices::Base::Invoicer - PAY_URL = 'https://paygate.kuna.io/hpp' - def create_invoice(money) - invoice = Invoice.create!(amount: money, order_public_id: order.public_id) - - params = { - amount: invoice.amount.to_f, - currency: currency, - payment_service: payment_service, - return_url: order.success_redirect, - callback_url: order.income_payment_system.callback_url - } - - params[:fields] = { required_field_name => order.income_account } unless payment_card_uah? - - response = client.create_deposit(params: params) - - raise "Can't create invoice: #{response['messages']}" if response['messages'] - - invoice.update!( - deposit_id: response['deposit_id'], - payment_invoice_id: response['payment_invoice_id'] - ) - end - - def pay_invoice_url - uri = URI.parse(PAY_URL) - uri.query = { cpi: invoice.reload.payment_invoice_id }.to_query - - uri - end - - private - - def payment_card_uah? - payway == 'visamc' && currency == 'uah' - end - - def currency - @currency ||= invoice.amount.currency.to_s.downcase - end - - def invoice - @invoice ||= Invoice.find_by!(order_public_id: order.public_id) - end - - def payway - @payway ||= order.income_wallet.payment_system.payway - end - - def payment_service - available_options = { - 'visamc' => "payment_card_#{currency}_hpp", - 'qiwi' => "qiwi_#{currency}_hpp" - } - available_options[payway] - end - - def required_field_name - required_field_for = { - 'visamc' => 'card_number', - 'qiwi' => 'phone' - } - required_field_for[payway] - end - - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class Kuna + class Invoicer < ::PaymentServices::Base::Invoicer + PAY_URL = 'https://paygate.kuna.io/hpp' + + def create_invoice(money) + invoice = Invoice.create!(amount: money, order_public_id: order.public_id) + + params = { + amount: invoice.amount.to_f, + currency: currency, + payment_service: payment_service, + return_url: order.success_redirect, + callback_url: order.income_payment_system.callback_url + } + + params[:fields] = { required_field_name => order.income_account } unless payment_card_uah? + + response = client.create_deposit(params: params) + + raise "Can't create invoice: #{response['messages']}" if response['messages'] + + invoice.update!( + deposit_id: response['deposit_id'], + payment_invoice_id: response['payment_invoice_id'] + ) + end + + def pay_invoice_url + uri = URI.parse(PAY_URL) + uri.query = { cpi: invoice.reload.payment_invoice_id }.to_query + + uri + end + + private + + def payment_card_uah? + payway == 'visamc' && currency == 'uah' + end + + def currency + @currency ||= invoice.amount.currency.to_s.downcase + end + + def invoice + @invoice ||= Invoice.find_by!(order_public_id: order.public_id) + end + + def payway + @payway ||= order.income_wallet.payment_system.payway + end + + def payment_service + available_options = { + 'visamc' => "payment_card_#{currency}_hpp", + 'qiwi' => "qiwi_#{currency}_hpp" + } + available_options[payway] + end + + def required_field_name + required_field_for = { + 'visamc' => 'card_number', + 'qiwi' => 'phone' + } + required_field_for[payway] + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/kuna/payout.rb b/lib/payment_services/kuna/payout.rb index 1ce3400a..8e96133c 100644 --- a/lib/payment_services/kuna/payout.rb +++ b/lib/payment_services/kuna/payout.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::Kuna - class Payout < ApplicationRecord - include Workflow - self.table_name = 'kuna_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid +module PaymentServices + class Kuna + class Payout < ApplicationRecord + include Workflow + + self.table_name = 'kuna_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed - end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def success? - provider_state == 'done' - end + def success? + provider_state == 'done' + end - def status_failed? - provider_state == 'canceled' || provider_state == 'unknown' + def status_failed? + provider_state == 'canceled' || provider_state == 'unknown' + end end end end diff --git a/lib/payment_services/kuna/payout_adapter.rb b/lib/payment_services/kuna/payout_adapter.rb index 90bb4d3b..c16ba4dd 100644 --- a/lib/payment_services/kuna/payout_adapter.rb +++ b/lib/payment_services/kuna/payout_adapter.rb @@ -3,73 +3,76 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Kuna - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - DEFAULT_GATEWAY = 'default' - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? +module PaymentServices + class Kuna + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + DEFAULT_GATEWAY = 'default' + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.payout_status(params: { id: payout.withdrawal_id }) + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? - raise "Can't get withdrawal details: #{response['messages']}" if response['messages'] + response = client.payout_status(params: { id: payout.withdrawal_id }) - payout.update!(provider_state: response['status']) if response['status'] - payout.confirm! if payout.success? - payout.fail! if payout.status_failed? + raise "Can't get withdrawal details: #{response['messages']}" if response['messages'] - response - end + payout.update!(provider_state: response['status']) if response['status'] + payout.confirm! if payout.success? + payout.fail! if payout.status_failed? - def payout - @payout ||= Payout.find_by(id: payout_id) - end + response + end - private + def payout + @payout ||= Payout.find_by(id: payout_id) + end - attr_accessor :payout_id + private - def make_payout(amount:, destination_account:, order_payout_id:) - @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id + attr_accessor :payout_id - params = { - amount: amount.to_d, - withdraw_type: currency, - withdraw_to: destination_account, - gateway: gateway - } - response = client.create_payout(params: params) - # NOTE: API returns an array of responses - response = response.first if response.is_a? Array + def make_payout(amount:, destination_account:, order_payout_id:) + @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id - raise "Can't process payout: #{response['messages']}" if response['messages'] + params = { + amount: amount.to_d, + withdraw_type: currency, + withdraw_to: destination_account, + gateway: gateway + } + response = client.create_payout(params: params) + # NOTE: API returns an array of responses + response = response.first if response.is_a? Array - payout.pay!(withdrawal_id: response['withdrawal_id']) if response['withdrawal_id'] - end + raise "Can't process payout: #{response['messages']}" if response['messages'] - def client - @client ||= begin - Client.new(api_key: api_key, secret_key: api_secret) + payout.pay!(withdrawal_id: response['withdrawal_id']) if response['withdrawal_id'] end - end - def gateway - return DEFAULT_GATEWAY unless wallet.payment_system.name == 'QIWI' + def client + @client ||= begin + Client.new(api_key: api_key, secret_key: api_secret) + end + end - "qiwi_#{currency}" - end + def gateway + return DEFAULT_GATEWAY unless wallet.payment_system.name == 'QIWI' - def currency - @currency ||= wallet.currency.to_s.downcase + "qiwi_#{currency}" + end + + def currency + @currency ||= wallet.currency.to_s.downcase + end end end end diff --git a/lib/payment_services/liquid/client.rb b/lib/payment_services/liquid/client.rb index 34128724..f73885c9 100644 --- a/lib/payment_services/liquid/client.rb +++ b/lib/payment_services/liquid/client.rb @@ -1,115 +1,118 @@ # frozen_string_literal: true -class PaymentServices::Liquid - class Client - include AutoLogger - TIMEOUT = 10 - API_URL = 'https://api.liquid.com' - API_VERSION = '2' - - def initialize(currency:, token_id:, api_key:) - @currency = currency - @token_id = token_id - @api_key = api_key - end - def address_transactions - params = { - transaction_type: 'funding', - currency: currency - } +module PaymentServices + class Liquid + class Client + include AutoLogger + TIMEOUT = 10 + API_URL = 'https://api.liquid.com' + API_VERSION = '2' + + def initialize(currency:, token_id:, api_key:) + @currency = currency + @token_id = token_id + @api_key = api_key + end - request_for('/transactions?', params: params) - end + def address_transactions + params = { + transaction_type: 'funding', + currency: currency + } - def wallet - wallets = request_for('/crypto_accounts') + request_for('/transactions?', params: params) + end - wallets.find { |w| w['currency'] == currency } - end + def wallet + wallets = request_for('/crypto_accounts') - def make_payout(params) - safely_parse http_request( - url: API_URL + "/crypto_withdrawals", - method: :POST, - body: { 'crypto_withdrawal' => params.merge(currency: currency) } - ) - end + wallets.find { |w| w['currency'] == currency } + end - def withdrawals - request_for('/crypto_withdrawals?', params: { currency: currency }) - end + def make_payout(params) + safely_parse http_request( + url: API_URL + "/crypto_withdrawals", + method: :POST, + body: { 'crypto_withdrawal' => params.merge(currency: currency) } + ) + end - private + def withdrawals + request_for('/crypto_withdrawals?', params: { currency: currency }) + end - attr_reader :currency, :token_id, :api_key + private - def request_for(path, params: nil) - url = API_URL + path - url += params.to_query if params + attr_reader :currency, :token_id, :api_key - safely_parse http_request( - url: url, - method: :GET - ) - end + def request_for(path, params: nil) + url = API_URL + path + url += params.to_query if params - def http_request(url:, method:, body: nil) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + safely_parse http_request( + url: url, + method: :GET + ) + end - def build_request(uri:, method:, body: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers(uri.to_s.delete_prefix(API_URL))) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, headers(uri.to_s.delete_prefix(API_URL))) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + def http_request(url:, method:, body: nil) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def build_request(uri:, method:, body: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers(uri.to_s.delete_prefix(API_URL))) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, headers(uri.to_s.delete_prefix(API_URL))) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - def headers(path) - { - 'Content-Type': 'application/json', - 'X-Quoine-API-Version': API_VERSION, - 'X-Quoine-Auth': build_signature(path) - } - end + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end - def build_signature(path) - auth_payload = { - path: path, - nonce: DateTime.now.strftime('%Q'), - token_id: token_id - } + def headers(path) + { + 'Content-Type': 'application/json', + 'X-Quoine-API-Version': API_VERSION, + 'X-Quoine-Auth': build_signature(path) + } + end - JWT.encode(auth_payload, api_key, 'HS256') - end + def build_signature(path) + auth_payload = { + path: path, + nonce: DateTime.now.strftime('%Q'), + token_id: token_id + } + + JWT.encode(auth_payload, api_key, 'HS256') + end - def safely_parse(response) - res = JSON.parse(response.body) - logger.info "Response: #{res}" - res - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + def safely_parse(response) + res = JSON.parse(response.body) + logger.info "Response: #{res}" + res + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/liquid/invoice.rb b/lib/payment_services/liquid/invoice.rb index 51dea9c0..94165814 100644 --- a/lib/payment_services/liquid/invoice.rb +++ b/lib/payment_services/liquid/invoice.rb @@ -1,40 +1,43 @@ # frozen_string_literal: true -class PaymentServices::Liquid - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'liquid_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class Liquid + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'liquid_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: transaction_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: transaction_id) + end end + state :cancelled end - state :cancelled - end - def complete_payment? - provider_state == 'confirmed' - end + def complete_payment? + provider_state == 'confirmed' + end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - @order ||= Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + def order + @order ||= Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end end end end diff --git a/lib/payment_services/liquid/invoicer.rb b/lib/payment_services/liquid/invoicer.rb index 163e9ce7..3b61b5ca 100644 --- a/lib/payment_services/liquid/invoicer.rb +++ b/lib/payment_services/liquid/invoicer.rb @@ -3,64 +3,67 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Liquid - class Invoicer < ::PaymentServices::Base::Invoicer - WALLET_NAME_GROUP = 'LIQUID_API_KEYS' - AddressTransactionsRequestFailed = Class.new StandardError - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end +module PaymentServices + class Liquid + class Invoicer < ::PaymentServices::Base::Invoicer + WALLET_NAME_GROUP = 'LIQUID_API_KEYS' + AddressTransactionsRequestFailed = Class.new StandardError - def prepare_invoice_and_get_wallet!(currency:, token_network:) - response = Client.new(currency: currency, token_id: api_wallet.merchant_id.to_i, api_key: api_key).wallet + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - PaymentServices::Base::Wallet.new(address: response['address'].first, name: response['address'].last) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + response = Client.new(currency: currency, token_id: api_wallet.merchant_id.to_i, api_key: api_key).wallet - def update_invoice_state! - transaction = transaction_for(invoice) - return if transaction.nil? + PaymentServices::Base::Wallet.new(address: response['address'].first, name: response['address'].last) + end - update_invoice_details(transaction: transaction) - invoice.pay!(payload: transaction) if invoice.complete_payment? - end + def update_invoice_state! + transaction = transaction_for(invoice) + return if transaction.nil? - def async_invoice_state_updater? - true - end + update_invoice_details(transaction: transaction) + invoice.pay!(payload: transaction) if invoice.complete_payment? + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def async_invoice_state_updater? + true + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def api_wallet - @api_wallet ||= Wallet.find_by(name_group: WALLET_NAME_GROUP) - end + private - def update_invoice_details(transaction:) - invoice.transaction_created_at ||= DateTime.strptime(transaction['created_at'].to_s, '%s').utc - invoice.transaction_id ||= transaction['transaction_hash'] - invoice.provider_state = transaction['state'] + def api_wallet + @api_wallet ||= Wallet.find_by(name_group: WALLET_NAME_GROUP) + end - invoice.save! - end + def update_invoice_details(transaction:) + invoice.transaction_created_at ||= DateTime.strptime(transaction['created_at'].to_s, '%s').utc + invoice.transaction_id ||= transaction['transaction_hash'] + invoice.provider_state = transaction['state'] - def transaction_for(invoice) - response = client.address_transactions - raise AddressTransactionsRequestFailed if response['message'] - return unless response['models'] + invoice.save! + end + + def transaction_for(invoice) + response = client.address_transactions + raise AddressTransactionsRequestFailed if response['message'] + return unless response['models'] - response['models'].find do |transaction| - received_amount = transaction['gross_amount'] - received_amount.to_d == invoice.amount.to_d && DateTime.strptime(transaction['created_at'].to_s, '%s').utc > invoice.created_at.utc + response['models'].find do |transaction| + received_amount = transaction['gross_amount'] + received_amount.to_d == invoice.amount.to_d && DateTime.strptime(transaction['created_at'].to_s, '%s').utc > invoice.created_at.utc + end end - end - def client - @client ||= Client.new(currency: order.income_wallet.currency.to_s, token_id: api_wallet.merchant_id.to_i, api_key: api_key) + def client + @client ||= Client.new(currency: order.income_wallet.currency.to_s, token_id: api_wallet.merchant_id.to_i, api_key: api_key) + end end end end diff --git a/lib/payment_services/liquid/payout.rb b/lib/payment_services/liquid/payout.rb index 96507819..fb932d95 100644 --- a/lib/payment_services/liquid/payout.rb +++ b/lib/payment_services/liquid/payout.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::Liquid - class Payout < ApplicationRecord - include Workflow - self.table_name = 'liquid_payouts' - SUCCESS_PAYOUT_STATE = 'processed' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :address, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid +module PaymentServices + class Liquid + class Payout < ApplicationRecord + include Workflow + self.table_name = 'liquid_payouts' + + SUCCESS_PAYOUT_STATE = 'processed' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :address, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + end + state :completed + state :failed end - state :paid do - event :confirm, transitions_to: :completed - end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def complete_payout? - status == SUCCESS_PAYOUT_STATE - end + def complete_payout? + status == SUCCESS_PAYOUT_STATE + end - def txid - withdrawal_id + def txid + withdrawal_id + end end end end diff --git a/lib/payment_services/liquid/payout_adapter.rb b/lib/payment_services/liquid/payout_adapter.rb index 446fdf00..cd9d374f 100644 --- a/lib/payment_services/liquid/payout_adapter.rb +++ b/lib/payment_services/liquid/payout_adapter.rb @@ -3,71 +3,74 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Liquid - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - WALLET_NAME_GROUP = 'LIQUID_API_KEYS' - - delegate :outcome_transaction_fee_amount, to: :payment_system - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - address: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? +module PaymentServices + class Liquid + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + WALLET_NAME_GROUP = 'LIQUID_API_KEYS' - response = client.withdrawals - raise "Can't get payout details: #{response['errors'].to_s}" if response['errors'] + delegate :outcome_transaction_fee_amount, to: :payment_system - withdrawal = response['models'].find do |withdrawal| - payout.withdrawal_id == withdrawal['id'] + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + address: destination_account, + order_payout_id: order_payout_id + ) end - payout.update!(status: withdrawal['state']) if withdrawal - payout.confirm! if payout.complete_payout? + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? - withdrawal - end + response = client.withdrawals + raise "Can't get payout details: #{response['errors'].to_s}" if response['errors'] - def payout - @payout ||= Payout.find_by(id: payout_id) - end + withdrawal = response['models'].find do |withdrawal| + payout.withdrawal_id == withdrawal['id'] + end - private + payout.update!(status: withdrawal['state']) if withdrawal + payout.confirm! if payout.complete_payout? - attr_accessor :payout_id + withdrawal + end - def api_wallet - @api_wallet ||= Wallet.find_by(name_group: WALLET_NAME_GROUP) - end + def payout + @payout ||= Payout.find_by(id: payout_id) + end - def make_payout(amount:, address:, order_payout_id:) - @payout_id = Payout.create!(amount: amount, address: address, order_payout_id: order_payout_id).id + private - payout_params = { - amount: amount.to_d.round(2) + (outcome_transaction_fee_amount || 0), - address: address, - payment_id: nil, - memo_type: nil, - memo_value: nil - } - response = client.make_payout(payout_params) + attr_accessor :payout_id - # NOTE: there are 2 types of error responses - errors = response['message'] || response['errors'] - raise "Can't process payout: #{errors.to_s}" if errors - raise 'Payout was not processed' unless response['id'] + def api_wallet + @api_wallet ||= Wallet.find_by(name_group: WALLET_NAME_GROUP) + end - payout.pay!(withdrawal_id: response['id']) - end + def make_payout(amount:, address:, order_payout_id:) + @payout_id = Payout.create!(amount: amount, address: address, order_payout_id: order_payout_id).id + + payout_params = { + amount: amount.to_d.round(2) + (outcome_transaction_fee_amount || 0), + address: address, + payment_id: nil, + memo_type: nil, + memo_value: nil + } + response = client.make_payout(payout_params) + + # NOTE: there are 2 types of error responses + errors = response['message'] || response['errors'] + raise "Can't process payout: #{errors.to_s}" if errors + raise 'Payout was not processed' unless response['id'] - def client - @client ||= Client.new(currency: wallet.currency.to_s, token_id: api_wallet.merchant_id.to_i, api_key: api_key) + payout.pay!(withdrawal_id: response['id']) + end + + def client + @client ||= Client.new(currency: wallet.currency.to_s, token_id: api_wallet.merchant_id.to_i, api_key: api_key) + end end end end diff --git a/lib/payment_services/manual_by_group/invoicer.rb b/lib/payment_services/manual_by_group/invoicer.rb index af628fa6..f5307a47 100644 --- a/lib/payment_services/manual_by_group/invoicer.rb +++ b/lib/payment_services/manual_by_group/invoicer.rb @@ -1,33 +1,36 @@ # frozen_string_literal: true -class PaymentServices::ManualByGroup - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - wallet = income_payment_system.select_next_wallet!(income_payment_system.wallets_available_for_transfers.income.where(name_group: income_payment_system.wallets_name_group.presence)) - wallet = income_payment_system.select_next_wallet!(wallet.incoming_children_wallets) if wallet && wallet.incoming_children_wallets.any? - PaymentServices::Base::Wallet.new( - address: wallet&.account, - name: wallet&.name, - memo: wallet&.memo, - name_group: wallet&.name_group - ) - end - def create_invoice(money) - true - end +module PaymentServices + class ManualByGroup + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + wallet = income_payment_system.select_next_wallet!(income_payment_system.wallets_available_for_transfers.income.where(name_group: income_payment_system.wallets_name_group.presence)) + wallet = income_payment_system.select_next_wallet!(wallet.incoming_children_wallets) if wallet && wallet.incoming_children_wallets.any? + PaymentServices::Base::Wallet.new( + address: wallet&.account, + name: wallet&.name, + memo: wallet&.memo, + name_group: wallet&.name_group + ) + end - def async_invoice_state_updater? - false - end + def create_invoice(money) + true + end - def invoice - nil - end + def async_invoice_state_updater? + false + end + + def invoice + nil + end - private + private - delegate :wallets_name_group, :wallets_available_for_transfers, to: :income_payment_system - delegate :income_payment_system, to: :order + delegate :wallets_name_group, :wallets_available_for_transfers, to: :income_payment_system + delegate :income_payment_system, to: :order + end end end diff --git a/lib/payment_services/master_processing/client.rb b/lib/payment_services/master_processing/client.rb index c7cfc274..932bef1d 100644 --- a/lib/payment_services/master_processing/client.rb +++ b/lib/payment_services/master_processing/client.rb @@ -2,86 +2,89 @@ require 'base64' -class PaymentServices::MasterProcessing - class Client < ::PaymentServices::Base::Client - API_URL = 'https://masterprocessingvip.ru/api/payment' - SHARED_PUBLIC_KEY = "04d08e67c1371b7201aabf03b933c23b540cce0c007a59137f50d70bb4cc5ebd860344af03a47b6bb503b05952200d264c5f8fee57d54da40cd38cb7b004c629c5" - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class MasterProcessing + class Client < ::PaymentServices::Base::Client + API_URL = 'https://masterprocessingvip.ru/api/payment' + SHARED_PUBLIC_KEY = "04d08e67c1371b7201aabf03b933c23b540cce0c007a59137f50d70bb4cc5ebd860344af03a47b6bb503b05952200d264c5f8fee57d54da40cd38cb7b004c629c5" - def create_invoice(params:, payway:) - safely_parse http_request( - url: create_invoice_endpoint(payway), - method: :POST, - body: params.to_json, - headers: build_headers(build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def process_payout(endpoint:, params:) - params.merge!(HSID: generate_hsid(params)) - safely_parse http_request( - url: "#{API_URL}/#{endpoint}", - method: :POST, - body: params.to_json, - headers: build_headers(build_signature(params)) - ) - end + def create_invoice(params:, payway:) + safely_parse http_request( + url: create_invoice_endpoint(payway), + method: :POST, + body: params.to_json, + headers: build_headers(build_signature(params)) + ) + end - def invoice_status(params:) - safely_parse http_request( - url: "#{API_URL}/get_invoice_order_info", - method: :POST, - body: params.to_json, - headers: build_headers(build_signature(params)) - ) - end + def process_payout(endpoint:, params:) + params.merge!(HSID: generate_hsid(params)) + safely_parse http_request( + url: "#{API_URL}/#{endpoint}", + method: :POST, + body: params.to_json, + headers: build_headers(build_signature(params)) + ) + end - def payout_status(params:) - safely_parse http_request( - url: "#{API_URL}/get_withdraw_order_info", - method: :POST, - body: params.to_json, - headers: build_headers(build_signature(params)) - ) - end + def invoice_status(params:) + safely_parse http_request( + url: "#{API_URL}/get_invoice_order_info", + method: :POST, + body: params.to_json, + headers: build_headers(build_signature(params)) + ) + end - private + def payout_status(params:) + safely_parse http_request( + url: "#{API_URL}/get_withdraw_order_info", + method: :POST, + body: params.to_json, + headers: build_headers(build_signature(params)) + ) + end - attr_reader :api_key, :secret_key + private - def build_headers(signature) - { - 'Content-Type' => 'application/json', - 'API-Key' => api_key, - 'Signature' => signature - } - end + attr_reader :api_key, :secret_key - def generate_hsid(params) - data = params.to_json - public_key_bin = [SHARED_PUBLIC_KEY].pack('H*') - group = OpenSSL::PKey::EC::Group.new("prime256v1") - public_point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_bin, 2)) - key = OpenSSL::PKey::EC.new(group) - key.generate_key! - key.public_key = public_point + def build_headers(signature) + { + 'Content-Type' => 'application/json', + 'API-Key' => api_key, + 'Signature' => signature + } + end - Base64.encode64(key.dsa_sign_asn1(data)) - end + def generate_hsid(params) + data = params.to_json + public_key_bin = [SHARED_PUBLIC_KEY].pack('H*') + group = OpenSSL::PKey::EC::Group.new("prime256v1") + public_point = OpenSSL::PKey::EC::Point.new(group, OpenSSL::BN.new(public_key_bin, 2)) + key = OpenSSL::PKey::EC.new(group) + key.generate_key! + key.public_key = public_point - def build_signature(request_body) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, request_body.to_json) - end + Base64.encode64(key.dsa_sign_asn1(data)) + end + + def build_signature(request_body) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, request_body.to_json) + end - def create_invoice_endpoint(payway) - if payway.cardh2h? || payway.qiwih2h? - "#{API_URL}/generate_invoice_h2h" - else - "#{API_URL}/generate_p2p_v3" + def create_invoice_endpoint(payway) + if payway.cardh2h? || payway.qiwih2h? + "#{API_URL}/generate_invoice_h2h" + else + "#{API_URL}/generate_p2p_v3" + end end end end diff --git a/lib/payment_services/master_processing/invoice.rb b/lib/payment_services/master_processing/invoice.rb index 39ed1bb3..86b16844 100644 --- a/lib/payment_services/master_processing/invoice.rb +++ b/lib/payment_services/master_processing/invoice.rb @@ -1,51 +1,54 @@ # frozen_string_literal: true -class PaymentServices::MasterProcessing - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'master_processing_invoices' +module PaymentServices + class MasterProcessing + class Invoice < ApplicationRecord + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'master_processing_invoices' - monetize :amount_cents, as: :amount + scope :ordered, -> { order(id: :desc) } - validates :amount_cents, :order_public_id, :state, presence: true + monetize :amount_cents, as: :amount - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: deposit_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: deposit_id) + end end + state :cancelled end - state :cancelled - end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - def update_state_by_provider(status) - update!(provider_state: status) + def update_state_by_provider(status) + update!(provider_state: status) - pay! if success? - cancel! if failed? - end + pay! if success? + cancel! if failed? + end - private + private - def success? - provider_state == 'payed' - end + def success? + provider_state == 'payed' + end - def failed? - provider_state == 'canceled' || provider_state == 'failed' + def failed? + provider_state == 'canceled' || provider_state == 'failed' + end end end end diff --git a/lib/payment_services/master_processing/invoicer.rb b/lib/payment_services/master_processing/invoicer.rb index 9304c424..9633fcd9 100644 --- a/lib/payment_services/master_processing/invoicer.rb +++ b/lib/payment_services/master_processing/invoicer.rb @@ -4,89 +4,92 @@ require_relative 'client' require_relative 'response' -class PaymentServices::MasterProcessing - class Invoicer < ::PaymentServices::Base::Invoicer - QIWI_DUMMY_CARD_TAIL = '9999' - AVAILABLE_PAYSOURCE_OPTIONS = { - 'visamc' => 'card', - 'cardh2h' => 'card', - 'qiwi' => 'qw', - 'qiwih2h' => 'qw' - } - - def create_invoice(money) - invoice = Invoice.create!(amount: money, order_public_id: order.public_id) - - params = { - amount: invoice.amount.to_i, - expireAt: PreliminaryOrder::MAX_LIVE.to_i, - comment: comment, - clientIP: client_ip, - paySourcesFilter: pay_source, - cardNumber: the_last_four_card_number, - email: order.email + +module PaymentServices + class MasterProcessing + class Invoicer < ::PaymentServices::Base::Invoicer + QIWI_DUMMY_CARD_TAIL = '9999' + AVAILABLE_PAYSOURCE_OPTIONS = { + 'visamc' => 'card', + 'cardh2h' => 'card', + 'qiwi' => 'qw', + 'qiwih2h' => 'qw' } - raw_response = client.create_invoice(params: params, payway: payway) - response = Response.build_from(raw_response: raw_response) + def create_invoice(money) + invoice = Invoice.create!(amount: money, order_public_id: order.public_id) - raise "Can't create invoice: #{response.error_message}" unless response.success? + params = { + amount: invoice.amount.to_i, + expireAt: PreliminaryOrder::MAX_LIVE.to_i, + comment: comment, + clientIP: client_ip, + paySourcesFilter: pay_source, + cardNumber: the_last_four_card_number, + email: order.email + } - invoice.update!( - deposit_id: response.deposit_id, - pay_invoice_url: response.pay_invoice_url - ) - end + raw_response = client.create_invoice(params: params, payway: payway) + response = Response.build_from(raw_response: raw_response) - def pay_invoice_url - invoice.reload.pay_invoice_url if invoice - end + raise "Can't create invoice: #{response.error_message}" unless response.success? - def async_invoice_state_updater? - true - end + invoice.update!( + deposit_id: response.deposit_id, + pay_invoice_url: response.pay_invoice_url + ) + end - def update_invoice_state! - response = client.invoice_status(params: { externalID: invoice.reload.deposit_id }) - raise "Can't get withdrawal details" unless response['statusName'] + def pay_invoice_url + invoice.reload.pay_invoice_url if invoice + end - invoice.update_state_by_provider(response['statusName']) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + response = client.invoice_status(params: { externalID: invoice.reload.deposit_id }) + raise "Can't get withdrawal details" unless response['statusName'] - private + invoice.update_state_by_provider(response['statusName']) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def comment - "Order: #{order.public_id}" - end + private - def client_ip - order.remote_ip || "" - end + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end - def payway - @payway ||= order.income_payment_system.payway.inquiry - end + def comment + "Order: #{order.public_id}" + end - def pay_source - AVAILABLE_PAYSOURCE_OPTIONS[payway] - end + def client_ip + order.remote_ip || "" + end - def the_last_four_card_number - return QIWI_DUMMY_CARD_TAIL if payway_qiwi? + def payway + @payway ||= order.income_payment_system.payway.inquiry + end - order.income_account.last(4) - end + def pay_source + AVAILABLE_PAYSOURCE_OPTIONS[payway] + end + + def the_last_four_card_number + return QIWI_DUMMY_CARD_TAIL if payway_qiwi? + + order.income_account.last(4) + end - def payway_qiwi? - payway.qiwi? || payway.qiwih2h? + def payway_qiwi? + payway.qiwi? || payway.qiwih2h? + end end end end diff --git a/lib/payment_services/master_processing/payout.rb b/lib/payment_services/master_processing/payout.rb index ebc73b95..94b3e44a 100644 --- a/lib/payment_services/master_processing/payout.rb +++ b/lib/payment_services/master_processing/payout.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::MasterProcessing - class Payout < ApplicationRecord - include Workflow - self.table_name = 'master_processing_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid +module PaymentServices + class MasterProcessing + class Payout < ApplicationRecord + include Workflow + + self.table_name = 'master_processing_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed - end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def success? - provider_state == 'success' - end + def success? + provider_state == 'success' + end - def status_failed? - provider_state == 'canceled' || provider_state == 'failed' + def status_failed? + provider_state == 'canceled' || provider_state == 'failed' + end end end end diff --git a/lib/payment_services/master_processing/payout_adapter.rb b/lib/payment_services/master_processing/payout_adapter.rb index efbf7f33..a3590b53 100644 --- a/lib/payment_services/master_processing/payout_adapter.rb +++ b/lib/payment_services/master_processing/payout_adapter.rb @@ -3,67 +3,70 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::MasterProcessing - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - PAYOUT_ACCEPTED_RESPONSE = 'Accepted' - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - @payout_id = payout_id - return if payout.pending? - - response = client.payout_status(params: { externalID: payout.withdrawal_id }) - - raise "Can't get withdrawal details" unless response['statusName'] - - payout.update!(provider_state: response['statusName']) - payout.confirm! if payout.success? - payout.fail! if payout.status_failed? - - response - end - - def payout - @payout ||= Payout.find_by(id: payout_id) - end - - private - - attr_accessor :payout_id - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id - - params = { - amount: amount.to_i, - recipient: destination_account, - uid: order_payout_id.to_s, - callbackURL: wallet.payment_system.callback_url - } - response = client.process_payout(endpoint: endpoint, params: params) - raise "Can't process payout: #{response}" unless response['status'] == PAYOUT_ACCEPTED_RESPONSE - - payout.pay!(withdrawal_id: response['externalID']) - end - - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) - end - def endpoint - { - 'visamc' => 'withdraw_to_card_v2', - 'cardh2h' => 'withdraw_to_card_v2', - 'qiwi' => 'withdraw_to_qiwi_v2', - 'qiwih2h' => 'withdraw_to_qiwi_v2' - }[wallet.payment_system.payway] +module PaymentServices + class MasterProcessing + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + PAYOUT_ACCEPTED_RESPONSE = 'Accepted' + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + @payout_id = payout_id + return if payout.pending? + + response = client.payout_status(params: { externalID: payout.withdrawal_id }) + + raise "Can't get withdrawal details" unless response['statusName'] + + payout.update!(provider_state: response['statusName']) + payout.confirm! if payout.success? + payout.fail! if payout.status_failed? + + response + end + + def payout + @payout ||= Payout.find_by(id: payout_id) + end + + private + + attr_accessor :payout_id + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout_id = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id).id + + params = { + amount: amount.to_i, + recipient: destination_account, + uid: order_payout_id.to_s, + callbackURL: wallet.payment_system.callback_url + } + response = client.process_payout(endpoint: endpoint, params: params) + raise "Can't process payout: #{response}" unless response['status'] == PAYOUT_ACCEPTED_RESPONSE + + payout.pay!(withdrawal_id: response['externalID']) + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end + + def endpoint + { + 'visamc' => 'withdraw_to_card_v2', + 'cardh2h' => 'withdraw_to_card_v2', + 'qiwi' => 'withdraw_to_qiwi_v2', + 'qiwih2h' => 'withdraw_to_qiwi_v2' + }[wallet.payment_system.payway] + end end end end diff --git a/lib/payment_services/master_processing/response.rb b/lib/payment_services/master_processing/response.rb index 997435d7..e7771a05 100644 --- a/lib/payment_services/master_processing/response.rb +++ b/lib/payment_services/master_processing/response.rb @@ -1,37 +1,40 @@ # frozen_string_literal: true -class PaymentServices::MasterProcessing - class Response - include Virtus.model - - attribute :deposit_id, String - attribute :pay_invoice_url, String - attribute :source, Hash - - def self.build_from(raw_response:) - new( - deposit_id: extract_deposit_id(raw_response), - pay_invoice_url: extract_pay_invoice_url(raw_response), - source: raw_response - ) - end - def success? - source['success'] - end +module PaymentServices + class MasterProcessing + class Response + include Virtus.model - def error_message - source['cause'] - end + attribute :deposit_id, String + attribute :pay_invoice_url, String + attribute :source, Hash - private + def self.build_from(raw_response:) + new( + deposit_id: extract_deposit_id(raw_response), + pay_invoice_url: extract_pay_invoice_url(raw_response), + source: raw_response + ) + end - def self.extract_deposit_id(raw_response) - raw_response['UID'] || raw_response['billID'] - end + def success? + source['success'] + end + + def error_message + source['cause'] + end + + private + + def self.extract_deposit_id(raw_response) + raw_response['UID'] || raw_response['billID'] + end - def self.extract_pay_invoice_url(raw_response) - raw_response['paymentURL'] || raw_response['paymentLinks']&.first + def self.extract_pay_invoice_url(raw_response) + raw_response['paymentURL'] || raw_response['paymentLinks']&.first + end end end end diff --git a/lib/payment_services/merchant_alikassa/client.rb b/lib/payment_services/merchant_alikassa/client.rb index 2fdfba87..d3e1d8e8 100644 --- a/lib/payment_services/merchant_alikassa/client.rb +++ b/lib/payment_services/merchant_alikassa/client.rb @@ -1,70 +1,73 @@ # frozen_string_literal: true -class PaymentServices::MerchantAlikassa - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api-merchant.alikassa.com/v1' - PAYMENTS_PRIVATE_KEY_FILE_PATH = 'config/alikassa_payments_privatekey.pem' - PAYOUTS_PRIVATE_KEY_FILE_PATH = 'config/alikassa_payouts_privatekey.pem' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class MerchantAlikassa + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api-merchant.alikassa.com/v1' + PAYMENTS_PRIVATE_KEY_FILE_PATH = 'config/alikassa_payments_privatekey.pem' + PAYOUTS_PRIVATE_KEY_FILE_PATH = 'config/alikassa_payouts_privatekey.pem' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payment", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def invoice_transaction(deposit_id:) - params = { id: deposit_id } - safely_parse http_request( - url: "#{API_URL}/payment/status", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payment", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) + ) + end - def create_payout(params:) - safely_parse http_request( - url: "#{API_URL}/payout", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params, PAYOUTS_PRIVATE_KEY_FILE_PATH)) - ) - end + def invoice_transaction(deposit_id:) + params = { id: deposit_id } + safely_parse http_request( + url: "#{API_URL}/payment/status", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) + ) + end - def payout_transaction(payout_id:) - params = { id: payout_id } - safely_parse http_request( - url: "#{API_URL}/payout/status", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params, PAYOUTS_PRIVATE_KEY_FILE_PATH)) - ) - end + def create_payout(params:) + safely_parse http_request( + url: "#{API_URL}/payout", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params, PAYOUTS_PRIVATE_KEY_FILE_PATH)) + ) + end - private + def payout_transaction(payout_id:) + params = { id: payout_id } + safely_parse http_request( + url: "#{API_URL}/payout/status", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params, PAYOUTS_PRIVATE_KEY_FILE_PATH)) + ) + end - attr_reader :api_key, :secret_key + private - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'Account' => "#{api_key}", - 'Sign' => signature - } - end + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'Account' => "#{api_key}", + 'Sign' => signature + } + end - def build_signature(params, private_key_file_path) - private_key = OpenSSL::PKey::read(File.read(private_key_file_path), secret_key) - signature = private_key.sign(OpenSSL::Digest::SHA1.new, params.to_json) - Base64.encode64(signature).gsub(/\n/, '') + def build_signature(params, private_key_file_path) + private_key = OpenSSL::PKey::read(File.read(private_key_file_path), secret_key) + signature = private_key.sign(OpenSSL::Digest::SHA1.new, params.to_json) + Base64.encode64(signature).gsub(/\n/, '') + end end end end diff --git a/lib/payment_services/merchant_alikassa/invoice.rb b/lib/payment_services/merchant_alikassa/invoice.rb index 40b80899..d5f53e23 100644 --- a/lib/payment_services/merchant_alikassa/invoice.rb +++ b/lib/payment_services/merchant_alikassa/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::MerchantAlikassa - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'paid' - FAILED_PROVIDER_STATES = %w(cancel fail) - self.table_name = 'merchant_alikassa_invoices' +module PaymentServices + class MerchantAlikassa + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'paid' + FAILED_PROVIDER_STATES = %w(cancel fail) - monetize :amount_cents, as: :amount + self.table_name = 'merchant_alikassa_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/merchant_alikassa/invoicer.rb b/lib/payment_services/merchant_alikassa/invoicer.rb index 10a7eb13..b74aee18 100644 --- a/lib/payment_services/merchant_alikassa/invoicer.rb +++ b/lib/payment_services/merchant_alikassa/invoicer.rb @@ -3,71 +3,74 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::MerchantAlikassa - class Invoicer < ::PaymentServices::Base::Invoicer - DEFAULT_USER_AGENT = 'Chrome/47.0.2526.111' - SBP_SERVICE = 'payment_card_sbp_rub_card' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise response['message'] if response['errors'] +module PaymentServices + class MerchantAlikassa + class Invoicer < ::PaymentServices::Base::Invoicer + DEFAULT_USER_AGENT = 'Chrome/47.0.2526.111' + SBP_SERVICE = 'payment_card_sbp_rub_card' - invoice.update!(deposit_id: response['id']) - PaymentServices::Base::Wallet.new( - address: response['cardNumber'], - name: response['cardHolderName'], - memo: response['bank'] - ) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise response['message'] if response['errors'] - def create_invoice(money) - invoice - end + invoice.update!(deposit_id: response['id']) + PaymentServices::Base::Wallet.new( + address: response['cardNumber'], + name: response['cardHolderName'], + memo: response['bank'] + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.invoice_transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['payment_status']) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.invoice_transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['payment_status']) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :income_payment_system, to: :order - delegate :currency, to: :income_payment_system - delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver + private - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + delegate :income_payment_system, to: :order + delegate :currency, to: :income_payment_system + delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver - def invoice_params - { - amount: invoice.amount.to_i, - order_id: order.public_id.to_s, - service: sbp? ? SBP_SERVICE : "payment_card_number_#{currency.to_s.downcase}_card", - customer_code: sbp? ? sbp_bank : card_bank, - customer_user_id: "#{Rails.env}_user_id_#{order.user_id}", - customer_ip: order.remote_ip, - customer_browser_user_agent: DEFAULT_USER_AGENT, - success_redirect_url: order.success_redirect, - fail_redirect_url: order.failed_redirect - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def invoice_params + { + amount: invoice.amount.to_i, + order_id: order.public_id.to_s, + service: sbp? ? SBP_SERVICE : "payment_card_number_#{currency.to_s.downcase}_card", + customer_code: sbp? ? sbp_bank : card_bank, + customer_user_id: "#{Rails.env}_user_id_#{order.user_id}", + customer_ip: order.remote_ip, + customer_browser_user_agent: DEFAULT_USER_AGENT, + success_redirect_url: order.success_redirect, + fail_redirect_url: order.failed_redirect + } + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/merchant_alikassa/payout.rb b/lib/payment_services/merchant_alikassa/payout.rb index be61b5b7..f75fd132 100644 --- a/lib/payment_services/merchant_alikassa/payout.rb +++ b/lib/payment_services/merchant_alikassa/payout.rb @@ -1,19 +1,22 @@ # frozen_string_literal: true -class PaymentServices::MerchantAlikassa - class Payout < ::PaymentServices::Base::FiatPayout - self.table_name = 'merchant_alikassa_payouts' - monetize :amount_cents, as: :amount +module PaymentServices + class MerchantAlikassa + class Payout < ::PaymentServices::Base::FiatPayout + self.table_name = 'merchant_alikassa_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == Invoice::SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == Invoice::SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? Invoice::FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? Invoice::FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/merchant_alikassa/payout_adapter.rb b/lib/payment_services/merchant_alikassa/payout_adapter.rb index f7f3baab..827fefc6 100644 --- a/lib/payment_services/merchant_alikassa/payout_adapter.rb +++ b/lib/payment_services/merchant_alikassa/payout_adapter.rb @@ -3,71 +3,74 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::MerchantAlikassa - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - Error = Class.new StandardError - P2P_RUB_SERVICE = 'payment_card_rub' - SBP_RUB_SERVICE = 'payment_card_sbp_rub' - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? - - transaction = client.payout_transaction(payout_id: payout.withdrawal_id) - payout.update_state_by_provider(transaction['payment_status']) if transaction - transaction - end - - private - - delegate :sbp_bank, :sbp?, to: :bank_resolver - - attr_reader :payout - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise Error, response['message'] if response['errors'] - - payout.pay!(withdrawal_id: response['id']) - end - - def payout_params - order = OrderPayout.find(payout.order_payout_id).order - number = sbp? ? order.outcome_phone[1..-1] : payout.destination_account - - params = { - amount: "%.2f" % payout.amount.to_f, - number: number, - order_id: order.public_id.to_s, - service: service - } - params[:customer_code] = sbp_bank if sbp? - params - end - - def service - sbp? ? SBP_RUB_SERVICE : P2P_RUB_SERVICE - end - - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end - - def order - OrderPayout.find(payout.order_payout_id).order - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class MerchantAlikassa + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + Error = Class.new StandardError + P2P_RUB_SERVICE = 'payment_card_rub' + SBP_RUB_SERVICE = 'payment_card_sbp_rub' + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? + + transaction = client.payout_transaction(payout_id: payout.withdrawal_id) + payout.update_state_by_provider(transaction['payment_status']) if transaction + transaction + end + + private + + delegate :sbp_bank, :sbp?, to: :bank_resolver + + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise Error, response['message'] if response['errors'] + + payout.pay!(withdrawal_id: response['id']) + end + + def payout_params + order = OrderPayout.find(payout.order_payout_id).order + number = sbp? ? order.outcome_phone[1..-1] : payout.destination_account + + params = { + amount: "%.2f" % payout.amount.to_f, + number: number, + order_id: order.public_id.to_s, + service: service + } + params[:customer_code] = sbp_bank if sbp? + params + end + + def service + sbp? ? SBP_RUB_SERVICE : P2P_RUB_SERVICE + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end + + def order + OrderPayout.find(payout.order_payout_id).order + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/merchant_alikassa_virtual/client.rb b/lib/payment_services/merchant_alikassa_virtual/client.rb index 6fd9caef..583ca6a4 100644 --- a/lib/payment_services/merchant_alikassa_virtual/client.rb +++ b/lib/payment_services/merchant_alikassa_virtual/client.rb @@ -1,50 +1,53 @@ # frozen_string_literal: true -class PaymentServices::MerchantAlikassaVirtual - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api-merchant.alikassa.com/v1' - PAYMENTS_PRIVATE_KEY_FILE_PATH = 'config/alikassa_payments_privatekey.pem' - - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payment", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) - ) - end - - def invoice_transaction(deposit_id:) - params = { id: deposit_id } - safely_parse http_request( - url: "#{API_URL}/payment/status", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'Account' => "#{api_key}", - 'Sign' => signature - } - end - def build_signature(params, private_key_file_path) - private_key = OpenSSL::PKey::read(File.read(private_key_file_path), secret_key) - signature = private_key.sign(OpenSSL::Digest::SHA1.new, params.to_json) - Base64.encode64(signature).gsub(/\n/, '') +module PaymentServices + class MerchantAlikassaVirtual + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api-merchant.alikassa.com/v1' + PAYMENTS_PRIVATE_KEY_FILE_PATH = 'config/alikassa_payments_privatekey.pem' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payment", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) + ) + end + + def invoice_transaction(deposit_id:) + params = { id: deposit_id } + safely_parse http_request( + url: "#{API_URL}/payment/status", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params, PAYMENTS_PRIVATE_KEY_FILE_PATH)) + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'Account' => "#{api_key}", + 'Sign' => signature + } + end + + def build_signature(params, private_key_file_path) + private_key = OpenSSL::PKey::read(File.read(private_key_file_path), secret_key) + signature = private_key.sign(OpenSSL::Digest::SHA1.new, params.to_json) + Base64.encode64(signature).gsub(/\n/, '') + end end end end diff --git a/lib/payment_services/merchant_alikassa_virtual/invoice.rb b/lib/payment_services/merchant_alikassa_virtual/invoice.rb index 344f6698..72725fc0 100644 --- a/lib/payment_services/merchant_alikassa_virtual/invoice.rb +++ b/lib/payment_services/merchant_alikassa_virtual/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::MerchantAlikassaVirtual - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'paid' - FAILED_PROVIDER_STATES = %w(cancel fail) - self.table_name = 'merchant_alikassa_virtual_invoices' +module PaymentServices + class MerchantAlikassaVirtual + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'paid' + FAILED_PROVIDER_STATES = %w(cancel fail) - monetize :amount_cents, as: :amount + self.table_name = 'merchant_alikassa_virtual_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/merchant_alikassa_virtual/invoicer.rb b/lib/payment_services/merchant_alikassa_virtual/invoicer.rb index 0b420f19..79322cc2 100644 --- a/lib/payment_services/merchant_alikassa_virtual/invoicer.rb +++ b/lib/payment_services/merchant_alikassa_virtual/invoicer.rb @@ -3,53 +3,56 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::MerchantAlikassaVirtual - class Invoicer < ::PaymentServices::Base::Invoicer - DEFAULT_USER_AGENT = 'Chrome/47.0.2526.111' - SERVICE = 'virtual_account_rub_hpp' - - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) - raise response['message'] if response['errors'] - - invoice.update!( - deposit_id: response['id'], - pay_url: response['url'] - ) - end - - def pay_invoice_url - invoice.reload.pay_url if invoice - end - - def async_invoice_state_updater? - true - end - - def update_invoice_state! - transaction = client.invoice_transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['payment_status']) - end - - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end - - private - - def invoice_params - { - amount: invoice.amount.to_i, - order_id: order.public_id.to_s, - service: SERVICE, - customer_ip: order.remote_ip, - customer_user_id: "#{Rails.env}_user_id_#{order.user_id}" - } - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class MerchantAlikassaVirtual + class Invoicer < ::PaymentServices::Base::Invoicer + DEFAULT_USER_AGENT = 'Chrome/47.0.2526.111' + SERVICE = 'virtual_account_rub_hpp' + + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) + raise response['message'] if response['errors'] + + invoice.update!( + deposit_id: response['id'], + pay_url: response['url'] + ) + end + + def pay_invoice_url + invoice.reload.pay_url if invoice + end + + def async_invoice_state_updater? + true + end + + def update_invoice_state! + transaction = client.invoice_transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['payment_status']) + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + private + + def invoice_params + { + amount: invoice.amount.to_i, + order_id: order.public_id.to_s, + service: SERVICE, + customer_ip: order.remote_ip, + customer_user_id: "#{Rails.env}_user_id_#{order.user_id}" + } + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/obmenka/client.rb b/lib/payment_services/obmenka/client.rb index b2f62e52..0affbdd7 100644 --- a/lib/payment_services/obmenka/client.rb +++ b/lib/payment_services/obmenka/client.rb @@ -3,137 +3,140 @@ require 'digest' require 'base64' -class PaymentServices::Obmenka - class Client - include AutoLogger - TIMEOUT = 30 - API_URL = 'https://acquiring_api.obmenka.ua/api' - - def initialize(merchant_id:, secret_key:) - @merchant_id = merchant_id - @secret_key = secret_key - end - def create_deposit(params:) - safely_parse http_request( - url: "#{API_URL}/einvoice/create", - method: :POST, - body: params - ) - end +module PaymentServices + class Obmenka + class Client + include AutoLogger + TIMEOUT = 30 + API_URL = 'https://acquiring_api.obmenka.ua/api' - def process_payment_data(public_id:, deposit_id:) - safely_parse http_request( - url: "#{API_URL}/einvoice/process", - method: :POST, - body: { - payment_id: public_id, - tracking: deposit_id - } - ) - end + def initialize(merchant_id:, secret_key:) + @merchant_id = merchant_id + @secret_key = secret_key + end - def invoice_status(public_id:, deposit_id:) - safely_parse http_request( - url: "#{API_URL}/einvoice/status", - method: :POST, - body: { - payment_id: public_id, - tracking: deposit_id - } - ) - end + def create_deposit(params:) + safely_parse http_request( + url: "#{API_URL}/einvoice/create", + method: :POST, + body: params + ) + end - def create_payout(params:) - safely_parse http_request( - url: "#{API_URL}/payment/create", - method: :POST, - body: params - ) - end + def process_payment_data(public_id:, deposit_id:) + safely_parse http_request( + url: "#{API_URL}/einvoice/process", + method: :POST, + body: { + payment_id: public_id, + tracking: deposit_id + } + ) + end - def process_payout(public_id:, withdrawal_id:) - safely_parse http_request( - url: "#{API_URL}/payment/process", - method: :POST, - body: { - payment_id: public_id, - tracking: withdrawal_id - } - ) - end + def invoice_status(public_id:, deposit_id:) + safely_parse http_request( + url: "#{API_URL}/einvoice/status", + method: :POST, + body: { + payment_id: public_id, + tracking: deposit_id + } + ) + end - def payout_status(public_id:, withdrawal_id:) - safely_parse http_request( - url: "#{API_URL}/payment/status", - method: :POST, - body: { - payment_id: public_id, - tracking: withdrawal_id - } - ) - end + def create_payout(params:) + safely_parse http_request( + url: "#{API_URL}/payment/create", + method: :POST, + body: params + ) + end - private + def process_payout(public_id:, withdrawal_id:) + safely_parse http_request( + url: "#{API_URL}/payment/process", + method: :POST, + body: { + payment_id: public_id, + tracking: withdrawal_id + } + ) + end - attr_reader :merchant_id, :secret_key + def payout_status(public_id:, withdrawal_id:) + safely_parse http_request( + url: "#{API_URL}/payment/status", + method: :POST, + body: { + payment_id: public_id, + tracking: withdrawal_id + } + ) + end - def http_request(url:, method:, body: nil) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + private - def build_request(uri:, method:, body: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers(build_signature(body))) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + attr_reader :merchant_id, :secret_key - def headers(signature) - { - 'Content-Type' => 'application/json', - 'DPAY_CLIENT' => merchant_id, - 'DPAY_SECURE' => signature - } - end + def http_request(url:, method:, body: nil) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def build_request(uri:, method:, body: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers(build_signature(body))) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - def build_signature(request_body) - sign_string = ActiveSupport::JSON.encode(request_body) - sign_string = Digest::SHA1.digest(sign_string) - sign_string = Base64.strict_encode64(sign_string) - sign_string = secret_key + sign_string + secret_key - sign_string = Digest::MD5.digest(sign_string) + def headers(signature) + { + 'Content-Type' => 'application/json', + 'DPAY_CLIENT' => merchant_id, + 'DPAY_SECURE' => signature + } + end - Base64.strict_encode64(sign_string) - end + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end + + def build_signature(request_body) + sign_string = ActiveSupport::JSON.encode(request_body) + sign_string = Digest::SHA1.digest(sign_string) + sign_string = Base64.strict_encode64(sign_string) + sign_string = secret_key + sign_string + secret_key + sign_string = Digest::MD5.digest(sign_string) + + Base64.strict_encode64(sign_string) + end - def safely_parse(response) - res = JSON.parse(response.body) - logger.info "Response: #{res}" - res - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response.body) + def safely_parse(response) + res = JSON.parse(response.body) + logger.info "Response: #{res}" + res + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/obmenka/invoice.rb b/lib/payment_services/obmenka/invoice.rb index ac028371..bd0f4ece 100644 --- a/lib/payment_services/obmenka/invoice.rb +++ b/lib/payment_services/obmenka/invoice.rb @@ -1,51 +1,54 @@ # frozen_string_literal: true -class PaymentServices::Obmenka - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'obmenka_invoices' +module PaymentServices + class Obmenka + class Invoice < ApplicationRecord + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'obmenka_invoices' - monetize :amount_cents, as: :amount + scope :ordered, -> { order(id: :desc) } - validates :amount_cents, :order_public_id, :state, presence: true + monetize :amount_cents, as: :amount - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount) + end end + state :cancelled end - state :cancelled - end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - pay! if success? - cancel! if failed? - end + pay! if success? + cancel! if failed? + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - private + private - def success? - provider_state == 'FINISHED' - end + def success? + provider_state == 'FINISHED' + end - def failed? - provider_state == 'FAILED' || provider_state == 'CANCELED' + def failed? + provider_state == 'FAILED' || provider_state == 'CANCELED' + end end end end diff --git a/lib/payment_services/obmenka/invoicer.rb b/lib/payment_services/obmenka/invoicer.rb index 40b1f4d4..e1ac0eac 100644 --- a/lib/payment_services/obmenka/invoicer.rb +++ b/lib/payment_services/obmenka/invoicer.rb @@ -3,67 +3,70 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Obmenka - class Invoicer < ::PaymentServices::Base::Invoicer - CARD_RU_SERVICE = 'visamaster.rur' - QIWI_SERVICE = 'qiwi' - def create_invoice(money) - invoice = Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_deposit(params: build_invoice_params) - raise "Can't create invoice: #{response['error']['message']}" if response['error'] - invoice.update!(deposit_id: response['tracking']) +module PaymentServices + class Obmenka + class Invoicer < ::PaymentServices::Base::Invoicer + CARD_RU_SERVICE = 'visamaster.rur' + QIWI_SERVICE = 'qiwi' - response = client.process_payment_data(public_id: invoice.order_public_id, deposit_id: invoice.deposit_id) - raise "Can't get pay url: #{response['error']['message']}" if response['error'] - invoice.update!(pay_url: response['pay_link']) - end + def create_invoice(money) + invoice = Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_deposit(params: build_invoice_params) + raise "Can't create invoice: #{response['error']['message']}" if response['error'] + invoice.update!(deposit_id: response['tracking']) - def pay_invoice_url - invoice.reload.pay_url if invoice - end + response = client.process_payment_data(public_id: invoice.order_public_id, deposit_id: invoice.deposit_id) + raise "Can't get pay url: #{response['error']['message']}" if response['error'] + invoice.update!(pay_url: response['pay_link']) + end - def async_invoice_state_updater? - true - end + def pay_invoice_url + invoice.reload.pay_url if invoice + end - def update_invoice_state! - response = client.invoice_status(public_id: invoice.order_public_id, deposit_id: invoice.deposit_id) - raise "Can't get invoice status: #{response['error']['message']}" if response['error'] + def async_invoice_state_updater? + true + end - invoice.update_state_by_provider(response['status']) if response['status'] - end + def update_invoice_state! + response = client.invoice_status(public_id: invoice.order_public_id, deposit_id: invoice.deposit_id) + raise "Can't get invoice status: #{response['error']['message']}" if response['error'] - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update_state_by_provider(response['status']) if response['status'] + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def build_invoice_params - { - payment_id: order.public_id.to_s, - currency: payment_service_by_payway, - amount: invoice.amount.to_f, - description: "Payment for #{order.public_id}", - sender: order.income_account, - success_url: order.success_redirect, - fail_url: order.failed_redirect - } - end + private - def payment_service_by_payway - available_options = { - 'visamc' => CARD_RU_SERVICE, - 'qiwi' => QIWI_SERVICE - } - available_options[order.income_wallet.payment_system.payway] - end + def build_invoice_params + { + payment_id: order.public_id.to_s, + currency: payment_service_by_payway, + amount: invoice.amount.to_f, + description: "Payment for #{order.public_id}", + sender: order.income_account, + success_url: order.success_redirect, + fail_url: order.failed_redirect + } + end + + def payment_service_by_payway + available_options = { + 'visamc' => CARD_RU_SERVICE, + 'qiwi' => QIWI_SERVICE + } + available_options[order.income_wallet.payment_system.payway] + end - def client - @client ||= begin - wallet = order.income_wallet - Client.new(merchant_id: wallet.merchant_id, secret_key: api_secret) + def client + @client ||= begin + wallet = order.income_wallet + Client.new(merchant_id: wallet.merchant_id, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/obmenka/payout.rb b/lib/payment_services/obmenka/payout.rb index 4b330384..01f9f5f6 100644 --- a/lib/payment_services/obmenka/payout.rb +++ b/lib/payment_services/obmenka/payout.rb @@ -1,56 +1,59 @@ # frozen_string_literal: true -class PaymentServices::Obmenka - class Payout < ApplicationRecord - include Workflow - self.table_name = 'obmenka_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed +module PaymentServices + class Obmenka + class Payout < ApplicationRecord + include Workflow + + self.table_name = 'obmenka_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - confirm! if success? - fail! if status_failed? - end + confirm! if success? + fail! if status_failed? + end - def public_id - "#{order_payout.order.public_id}-#{order_payout.id}" - end + def public_id + "#{order_payout.order.public_id}-#{order_payout.id}" + end - private + private - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) - end + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end - def success? - provider_state == 'PAYED' - end + def success? + provider_state == 'PAYED' + end - def status_failed? - provider_state == 'CANCELED' || provider_state == 'FAILED' + def status_failed? + provider_state == 'CANCELED' || provider_state == 'FAILED' + end end end end diff --git a/lib/payment_services/obmenka/payout_adapter.rb b/lib/payment_services/obmenka/payout_adapter.rb index 743611f5..83b62813 100644 --- a/lib/payment_services/obmenka/payout_adapter.rb +++ b/lib/payment_services/obmenka/payout_adapter.rb @@ -3,64 +3,67 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Obmenka - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - CARD_RU_SERVICE = 'visamaster.rur' - QIWI_SERVICE = 'qiwi' - Error = Class.new StandardError - PayoutStatusRequestFailed = Class.new Error - PayoutCreateRequestFailed = Class.new Error - PayoutProcessRequestFailed = Class.new Error +module PaymentServices + class Obmenka + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + CARD_RU_SERVICE = 'visamaster.rur' + QIWI_SERVICE = 'qiwi' - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end + Error = Class.new StandardError + PayoutStatusRequestFailed = Class.new Error + PayoutCreateRequestFailed = Class.new Error + PayoutProcessRequestFailed = Class.new Error - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.payout_status(public_id: payout.public_id, withdrawal_id: payout.withdrawal_id) - raise PayoutStatusRequestFailed, "Can't get payout status: #{response['error']['message']}" if response['error'] + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - payout.update_state_by_provider(response['status']) if response['status'] - response - end + response = client.payout_status(public_id: payout.public_id, withdrawal_id: payout.withdrawal_id) + raise PayoutStatusRequestFailed, "Can't get payout status: #{response['error']['message']}" if response['error'] - private + payout.update_state_by_provider(response['status']) if response['status'] + response + end - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - payout_params = { - recipient: destination_account, - currency: payment_service_by_payway, - amount: amount.to_f, - description: "Payout #{payout.public_id}", - payment_id: payout.public_id - } - response = client.create_payout(params: payout_params) - raise PayoutCreateRequestFailed, "Can't create payout: #{response['error']['message']}" if response['error'] + private - payout.pay!(withdrawal_id: response['tracking']) - response = client.process_payout(public_id: payout.public_id, withdrawal_id: payout.withdrawal_id) - raise PayoutProcessRequestFailed, "Can't process payout: #{response['error']['message']}" if response['error'] - end + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + payout_params = { + recipient: destination_account, + currency: payment_service_by_payway, + amount: amount.to_f, + description: "Payout #{payout.public_id}", + payment_id: payout.public_id + } + response = client.create_payout(params: payout_params) + raise PayoutCreateRequestFailed, "Can't create payout: #{response['error']['message']}" if response['error'] - def payment_service_by_payway - available_options = { - 'visamc' => CARD_RU_SERVICE, - 'qiwi' => QIWI_SERVICE - } - available_options[wallet.payment_system.payway] - end + payout.pay!(withdrawal_id: response['tracking']) + response = client.process_payout(public_id: payout.public_id, withdrawal_id: payout.withdrawal_id) + raise PayoutProcessRequestFailed, "Can't process payout: #{response['error']['message']}" if response['error'] + end + + def payment_service_by_payway + available_options = { + 'visamc' => CARD_RU_SERVICE, + 'qiwi' => QIWI_SERVICE + } + available_options[wallet.payment_system.payway] + end - def client - @client ||= Client.new(merchant_id: wallet.merchant_id, secret_key: api_secret) + def client + @client ||= Client.new(merchant_id: wallet.merchant_id, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/oko_otc/client.rb b/lib/payment_services/oko_otc/client.rb index 76232e45..94ee9fbb 100644 --- a/lib/payment_services/oko_otc/client.rb +++ b/lib/payment_services/oko_otc/client.rb @@ -1,47 +1,50 @@ # frozen_string_literal: true -class PaymentServices::OkoOtc - class Client < ::PaymentServices::Base::Client - API_URL = 'https://oko-otc.ru/api/v2/payment' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def process_payout(params:) - safely_parse http_request( - url: "#{API_URL}/create_withdraw", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end - - def payout_status(withdrawal_id:) - safely_parse http_request( - url: "#{API_URL}/fetch_order_by_uid/#{withdrawal_id}", - method: :GET, - headers: build_headers(signature: '') - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_signature(params) - sign_string = [params[:sum], params[:wallet], params[:orderUID], ''].join(';') - OpenSSL::HMAC.hexdigest('SHA512', secret_key, sign_string) - end - - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'Accept' => 'application/json', - 'Authorization' => api_key, - 'Signature' => signature - } +module PaymentServices + class OkoOtc + class Client < ::PaymentServices::Base::Client + API_URL = 'https://oko-otc.ru/api/v2/payment' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def process_payout(params:) + safely_parse http_request( + url: "#{API_URL}/create_withdraw", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end + + def payout_status(withdrawal_id:) + safely_parse http_request( + url: "#{API_URL}/fetch_order_by_uid/#{withdrawal_id}", + method: :GET, + headers: build_headers(signature: '') + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_signature(params) + sign_string = [params[:sum], params[:wallet], params[:orderUID], ''].join(';') + OpenSSL::HMAC.hexdigest('SHA512', secret_key, sign_string) + end + + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'Accept' => 'application/json', + 'Authorization' => api_key, + 'Signature' => signature + } + end end end end diff --git a/lib/payment_services/oko_otc/payout.rb b/lib/payment_services/oko_otc/payout.rb index 1a8728c2..1328a309 100644 --- a/lib/payment_services/oko_otc/payout.rb +++ b/lib/payment_services/oko_otc/payout.rb @@ -1,51 +1,54 @@ # frozen_string_literal: true -class PaymentServices::OkoOtc - class Payout < ApplicationRecord - SUCCESS_PROVIDER_STATE = 'Выплачена' - FAILED_PROVIDER_STATE = 'Отмененная' - include Workflow +module PaymentServices + class OkoOtc + class Payout < ApplicationRecord + SUCCESS_PROVIDER_STATE = 'Выплачена' + FAILED_PROVIDER_STATE = 'Отмененная' - self.table_name = 'oko_otc_payouts' + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'oko_otc_payouts' - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, :order_payout_id, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, :order_payout_id, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - confirm! if provider_succeed? - fail! if provider_failed? - end + confirm! if provider_succeed? + fail! if provider_failed? + end - private + private - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/oko_otc/payout_adapter.rb b/lib/payment_services/oko_otc/payout_adapter.rb index 6262807b..91def610 100644 --- a/lib/payment_services/oko_otc/payout_adapter.rb +++ b/lib/payment_services/oko_otc/payout_adapter.rb @@ -3,75 +3,78 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::OkoOtc - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class OkoOtc + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - order = OrderPayout.find(payout.order_payout_id).order - response = client.payout_status(withdrawal_id: "#{order.public_id}-#{payout.order_payout_id}") + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - raise "Can't get withdraw history. Error Code: #{response['errCode']}" unless response['totalLen'] + order = OrderPayout.find(payout.order_payout_id).order + response = client.payout_status(withdrawal_id: "#{order.public_id}-#{payout.order_payout_id}") - payout.update_state_by_provider(provider_state(response)) - response - end + raise "Can't get withdraw history. Error Code: #{response['errCode']}" unless response['totalLen'] - private - - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - order = OrderPayout.find(order_payout_id).order - - params = { - sum: amount.to_i, - currencyFrom: amount.currency.to_s, - wallet: destination_account, - bank: provider_bank, - orderUID: "#{order.public_id}-#{order_payout_id}" - } - curr = amount.currency.to_s.downcase.inquiry - params[:cardholder] = order.outcome_fio if curr.eur? || curr.usd? - params[:cardExpiration] = card_expiration(order) if curr.eur? || curr.azn? - if curr.usdt? - params[:sumInRub] = usdt_to_rub(amount: amount).to_i - params[:sum] = 1 + payout.update_state_by_provider(provider_state(response)) + response end - response = client.process_payout(params: params) - raise "Can't create payout. Error Code: #{response['errCode']}" unless response['status'] - - payout.pay!(withdrawal_id: response['orderID']) - end + private + + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + order = OrderPayout.find(order_payout_id).order + + params = { + sum: amount.to_i, + currencyFrom: amount.currency.to_s, + wallet: destination_account, + bank: provider_bank, + orderUID: "#{order.public_id}-#{order_payout_id}" + } + curr = amount.currency.to_s.downcase.inquiry + params[:cardholder] = order.outcome_fio if curr.eur? || curr.usd? + params[:cardExpiration] = card_expiration(order) if curr.eur? || curr.azn? + if curr.usdt? + params[:sumInRub] = usdt_to_rub(amount: amount).to_i + params[:sum] = 1 + end + + response = client.process_payout(params: params) + raise "Can't create payout. Error Code: #{response['errCode']}" unless response['status'] + + payout.pay!(withdrawal_id: response['orderID']) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) - end + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end - def card_expiration(order) - month, year = order.payment_card_exp_date.split('/') - year.length == 2 ? "#{month}/20#{year}" : order.payment_card_exp_date - end + def card_expiration(order) + month, year = order.payment_card_exp_date.split('/') + year.length == 2 ? "#{month}/20#{year}" : order.payment_card_exp_date + end - def provider_state(response) - response['data'].first.dig('orderStats', 'statusName') - end + def provider_state(response) + response['data'].first.dig('orderStats', 'statusName') + end - def provider_bank - @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank - end + def provider_bank + @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank + end - def usdt_to_rub(amount:) - Gera::ExchangeRate.find_by(ps_from_id: 69, ps_to_id: 72).direction_rate.reverse_exchange(amount).to_i + def usdt_to_rub(amount:) + Gera::ExchangeRate.find_by(ps_from_id: 69, ps_to_id: 72).direction_rate.reverse_exchange(amount).to_i + end end end end diff --git a/lib/payment_services/one_crypto/client.rb b/lib/payment_services/one_crypto/client.rb index 44c49924..b69c0da2 100644 --- a/lib/payment_services/one_crypto/client.rb +++ b/lib/payment_services/one_crypto/client.rb @@ -1,62 +1,65 @@ # frozen_string_literal: true -class PaymentServices::OneCrypto - class Client < ::PaymentServices::Base::Client - API_URL = 'https://apiv2.expay.cash/api/transaction' - MERCHANT_ID = 'kassa.cc' - - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/create/in", - method: :POST, - body: params.merge(client_merchant_id: MERCHANT_ID).to_json, - headers: build_headers(signature: build_signature(params)) - ) - end +module PaymentServices + class OneCrypto + class Client < ::PaymentServices::Base::Client + API_URL = 'https://apiv2.expay.cash/api/transaction' + MERCHANT_ID = 'kassa.cc' - def create_payout(params:) - safely_parse http_request( - url: "#{API_URL}/create/out", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def transaction(tracker_id:) - params = { tracker_id: tracker_id } - safely_parse(http_request( - url: "#{API_URL}/get", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ))['transaction'] - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/create/in", + method: :POST, + body: params.merge(client_merchant_id: MERCHANT_ID).to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - private + def create_payout(params:) + safely_parse http_request( + url: "#{API_URL}/create/out", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - attr_reader :api_key, :secret_key + def transaction(tracker_id:) + params = { tracker_id: tracker_id } + safely_parse(http_request( + url: "#{API_URL}/get", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ))['transaction'] + end - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'ApiPublic' => api_key, - 'TimeStamp' => timestamp_string, - 'Signature' => signature - } - end + private - def build_signature(params) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, timestamp_string + params.to_json) - end + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'ApiPublic' => api_key, + 'TimeStamp' => timestamp_string, + 'Signature' => signature + } + end + + def build_signature(params) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, timestamp_string + params.to_json) + end - def timestamp_string - @timestamp_string ||= Time.now.to_i.to_s + def timestamp_string + @timestamp_string ||= Time.now.to_i.to_s + end end end end diff --git a/lib/payment_services/one_crypto/invoice.rb b/lib/payment_services/one_crypto/invoice.rb index ecc8995d..54f32e16 100644 --- a/lib/payment_services/one_crypto/invoice.rb +++ b/lib/payment_services/one_crypto/invoice.rb @@ -1,40 +1,43 @@ # frozen_string_literal: true -class PaymentServices::OneCrypto - class Invoice < ::PaymentServices::Base::CryptoInvoice - INITIAL_PROVIDER_STATE = 'ACCEPTED' - self.table_name = 'one_crypto_invoices' +module PaymentServices + class OneCrypto + class Invoice < ::PaymentServices::Base::CryptoInvoice + INITIAL_PROVIDER_STATE = 'ACCEPTED' - monetize :amount_cents, as: :amount + self.table_name = 'one_crypto_invoices' - def update_state_by_transaction!(transaction) - validate_transaction_amount!(transaction: transaction) + monetize :amount_cents, as: :amount - bind_transaction! if pending? - update!( - provider_state: transaction.status, - transaction_id: transaction.transaction_id - ) - pay!(payload: transaction) if transaction.succeed? - cancel! if transaction.failed? - end + def update_state_by_transaction!(transaction) + validate_transaction_amount!(transaction: transaction) - def transaction_created_at - nil - end + bind_transaction! if pending? + update!( + provider_state: transaction.status, + transaction_id: transaction.transaction_id + ) + pay!(payload: transaction) if transaction.succeed? + cancel! if transaction.failed? + end - private + def transaction_created_at + nil + end - delegate :income_payment_system, to: :order - delegate :token_network, to: :income_payment_system + private - def amount_provider_currency - @amount_provider_currency ||= PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: amount_currency, token_network: token_network).provider_crypto_currency - end + delegate :income_payment_system, to: :order + delegate :token_network, to: :income_payment_system + + def amount_provider_currency + @amount_provider_currency ||= PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: amount_currency, token_network: token_network).provider_crypto_currency + end - def validate_transaction_amount!(transaction:) - raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + def validate_transaction_amount!(transaction:) + raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + end end end end diff --git a/lib/payment_services/one_crypto/invoicer.rb b/lib/payment_services/one_crypto/invoicer.rb index 4df074de..fa7140bc 100644 --- a/lib/payment_services/one_crypto/invoicer.rb +++ b/lib/payment_services/one_crypto/invoicer.rb @@ -4,44 +4,47 @@ require_relative 'client' require_relative 'transaction' -class PaymentServices::OneCrypto - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - invoice_params = { - token: PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: currency, token_network: token_network).provider_crypto_currency, - client_transaction_id: order.id_in_unixtime.to_s, - call_back_url: order.income_payment_system.callback_url - } - - response = client.create_invoice(params: invoice_params) - raise "Can't create invoice: #{response['description']}" unless response['status'] == Invoice::INITIAL_PROVIDER_STATE - - PaymentServices::Base::Wallet.new(address: response['refer'], name: response['tracker_id']) - end - - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - invoice.update!(deposit_id: order.income_wallet.name) - end - - def async_invoice_state_updater? - true - end - - def update_invoice_state! - raw_transaction = client.transaction(tracker_id: invoice.deposit_id) - transaction = Transaction.build_from(raw_transaction) - invoice.update_state_by_transaction!(transaction) - end - - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end - - private - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class OneCrypto + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + invoice_params = { + token: PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: currency, token_network: token_network).provider_crypto_currency, + client_transaction_id: order.id_in_unixtime.to_s, + call_back_url: order.income_payment_system.callback_url + } + + response = client.create_invoice(params: invoice_params) + raise "Can't create invoice: #{response['description']}" unless response['status'] == Invoice::INITIAL_PROVIDER_STATE + + PaymentServices::Base::Wallet.new(address: response['refer'], name: response['tracker_id']) + end + + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + invoice.update!(deposit_id: order.income_wallet.name) + end + + def async_invoice_state_updater? + true + end + + def update_invoice_state! + raw_transaction = client.transaction(tracker_id: invoice.deposit_id) + transaction = Transaction.build_from(raw_transaction) + invoice.update_state_by_transaction!(transaction) + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + private + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/one_crypto/payout.rb b/lib/payment_services/one_crypto/payout.rb index bbec5292..4d77aca0 100644 --- a/lib/payment_services/one_crypto/payout.rb +++ b/lib/payment_services/one_crypto/payout.rb @@ -1,13 +1,16 @@ # frozen_string_literal: true -class PaymentServices::OneCrypto - class Payout < ::PaymentServices::Base::CryptoPayout - self.table_name = 'one_crypto_payouts' - monetize :amount_cents, as: :amount +module PaymentServices + class OneCrypto + class Payout < ::PaymentServices::Base::CryptoPayout + self.table_name = 'one_crypto_payouts' - def txid - '' + monetize :amount_cents, as: :amount + + def txid + '' + end end end end diff --git a/lib/payment_services/one_crypto/payout_adapter.rb b/lib/payment_services/one_crypto/payout_adapter.rb index eb25af49..1784b353 100644 --- a/lib/payment_services/one_crypto/payout_adapter.rb +++ b/lib/payment_services/one_crypto/payout_adapter.rb @@ -4,55 +4,58 @@ require_relative 'payout' require_relative 'transaction' -class PaymentServices::OneCrypto - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - INITIAL_PROVIDER_STATE = 'ACCEPTED' - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? - - raw_transaction = client.transaction(tracker_id: payout.withdrawal_id) - transaction = Transaction.build_from(raw_transaction) - payout.update_state_by_provider!(transaction) - raw_transaction - end - - private - - attr_reader :payout - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise "Can't create payout: #{response['description']}" unless response['status'] == INITIAL_PROVIDER_STATE - - payout.pay!(withdrawal_id: response['tracker_id']) - end - - def payout_params - { - token: currency, - amount: payout.amount.to_f, - client_transaction_id: "#{payout.order_payout_id}-#{payout.id}", - receiver: payout.destination_account - } - end - - def currency - PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: wallet.currency, token_network: wallet.payment_system.token_network).provider_crypto_currency - end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class OneCrypto + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + INITIAL_PROVIDER_STATE = 'ACCEPTED' + + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? + + raw_transaction = client.transaction(tracker_id: payout.withdrawal_id) + transaction = Transaction.build_from(raw_transaction) + payout.update_state_by_provider!(transaction) + raw_transaction + end + + private + + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise "Can't create payout: #{response['description']}" unless response['status'] == INITIAL_PROVIDER_STATE + + payout.pay!(withdrawal_id: response['tracker_id']) + end + + def payout_params + { + token: currency, + amount: payout.amount.to_f, + client_transaction_id: "#{payout.order_payout_id}-#{payout.id}", + receiver: payout.destination_account + } + end + + def currency + PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: wallet.currency, token_network: wallet.payment_system.token_network).provider_crypto_currency + end + + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/one_crypto/transaction.rb b/lib/payment_services/one_crypto/transaction.rb index 72040b19..13ff5858 100644 --- a/lib/payment_services/one_crypto/transaction.rb +++ b/lib/payment_services/one_crypto/transaction.rb @@ -1,44 +1,47 @@ # frozen_string_literal: true -class PaymentServices::OneCrypto - class Transaction - SUCCESS_PROVIDER_STATE = 'SUCCESS' - FAILED_PROVIDER_STATE = 'ERROR' - - include Virtus.model - - attribute :amount, Float - attribute :currency, String - attribute :status, String - attribute :transaction_id, String - attribute :fee, Float - attribute :source, Hash - - def self.build_from(raw_transaction) - new( - amount: raw_transaction['amount'].to_f, - currency: raw_transaction['token'], - status: raw_transaction['status'], - transaction_id: raw_transaction['hash'], - fee: raw_transaction['transaction_commission'].to_f, - source: raw_transaction - ) - end - - def to_s - source.to_s - end - - def valid_amount?(payout_amount, payout_currency) - (amount.zero? || amount == payout_amount) && currency == payout_currency - end - - def succeed? - status == SUCCESS_PROVIDER_STATE - end - def failed? - status == FAILED_PROVIDER_STATE +module PaymentServices + class OneCrypto + class Transaction + SUCCESS_PROVIDER_STATE = 'SUCCESS' + FAILED_PROVIDER_STATE = 'ERROR' + + include Virtus.model + + attribute :amount, Float + attribute :currency, String + attribute :status, String + attribute :transaction_id, String + attribute :fee, Float + attribute :source, Hash + + def self.build_from(raw_transaction) + new( + amount: raw_transaction['amount'].to_f, + currency: raw_transaction['token'], + status: raw_transaction['status'], + transaction_id: raw_transaction['hash'], + fee: raw_transaction['transaction_commission'].to_f, + source: raw_transaction + ) + end + + def to_s + source.to_s + end + + def valid_amount?(payout_amount, payout_currency) + (amount.zero? || amount == payout_amount) && currency == payout_currency + end + + def succeed? + status == SUCCESS_PROVIDER_STATE + end + + def failed? + status == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/panda_pay/client.rb b/lib/payment_services/panda_pay/client.rb index afdf8a7f..6c45e188 100644 --- a/lib/payment_services/panda_pay/client.rb +++ b/lib/payment_services/panda_pay/client.rb @@ -1,52 +1,55 @@ # frozen_string_literal: true -class PaymentServices::PandaPay - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.pandapay24.com' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - timestamp = Time.now.utc.to_i - params_as_json = params.to_json - request_body = "#{timestamp}#{params_as_json}" - - safely_parse http_request( - url: "#{API_URL}/orders", - method: :POST, - body: params_as_json, - headers: build_headers(signature: build_signature(request_body), timestamp: timestamp) - ) - end - - def invoice(deposit_id:) - timestamp = Time.now.utc.to_i - request_body = "#{timestamp}" - - safely_parse http_request( - url: "#{API_URL}/orders/#{deposit_id}", - method: :GET, - headers: build_headers(signature: build_signature(request_body), timestamp: timestamp) - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_headers(signature:, timestamp:) - { - 'X-API-Key' => api_key, - 'X-Signature' => signature, - 'X-Timestamp' => timestamp.to_s - } - end - - def build_signature(request_body) - OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, request_body) +module PaymentServices + class PandaPay + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.pandapay24.com' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + timestamp = Time.now.utc.to_i + params_as_json = params.to_json + request_body = "#{timestamp}#{params_as_json}" + + safely_parse http_request( + url: "#{API_URL}/orders", + method: :POST, + body: params_as_json, + headers: build_headers(signature: build_signature(request_body), timestamp: timestamp) + ) + end + + def invoice(deposit_id:) + timestamp = Time.now.utc.to_i + request_body = "#{timestamp}" + + safely_parse http_request( + url: "#{API_URL}/orders/#{deposit_id}", + method: :GET, + headers: build_headers(signature: build_signature(request_body), timestamp: timestamp) + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_headers(signature:, timestamp:) + { + 'X-API-Key' => api_key, + 'X-Signature' => signature, + 'X-Timestamp' => timestamp.to_s + } + end + + def build_signature(request_body) + OpenSSL::HMAC.hexdigest(OpenSSL::Digest.new('sha256'), secret_key, request_body) + end end end end diff --git a/lib/payment_services/panda_pay/invoice.rb b/lib/payment_services/panda_pay/invoice.rb index 322a3d2c..1fefa12b 100644 --- a/lib/payment_services/panda_pay/invoice.rb +++ b/lib/payment_services/panda_pay/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::PandaPay - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'completed' - FAILED_PROVIDER_STATES = %w(traderNotFound timeout canceled) - self.table_name = 'panda_pay_invoices' +module PaymentServices + class PandaPay + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'completed' + FAILED_PROVIDER_STATES = %w(traderNotFound timeout canceled) - monetize :amount_cents, as: :amount + self.table_name = 'panda_pay_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/panda_pay/invoicer.rb b/lib/payment_services/panda_pay/invoicer.rb index 97c62b58..18d2fc18 100644 --- a/lib/payment_services/panda_pay/invoicer.rb +++ b/lib/payment_services/panda_pay/invoicer.rb @@ -3,65 +3,68 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::PandaPay - class Invoicer < ::PaymentServices::Base::Invoicer - CURRENCY_TO_COUNTRY = { - 'KZT' => 'KAZ', - 'AZN' => 'AZE', - 'TJS' => 'TJK' - } - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise response['error'] if response['error'] +module PaymentServices + class PandaPay + class Invoicer < ::PaymentServices::Base::Invoicer + CURRENCY_TO_COUNTRY = { + 'KZT' => 'KAZ', + 'AZN' => 'AZE', + 'TJS' => 'TJK' + } - invoice.update!(deposit_id: response['uuid']) - requisite_data = response['requisite_data'] + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise response['error'] if response['error'] - PaymentServices::Base::Wallet.new( - address: requisite_data['requisites'], - name: requisite_data['owner_full_name'], - memo: requisite_data['bank_name_ru'] - ) - end + invoice.update!(deposit_id: response['uuid']) + requisite_data = response['requisite_data'] - def create_invoice(money) - invoice - end + PaymentServices::Base::Wallet.new( + address: requisite_data['requisites'], + name: requisite_data['owner_full_name'], + memo: requisite_data['bank_name_ru'] + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.invoice(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['status']) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.invoice(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['status']) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_params - { - amount_rub: invoice.amount.to_f.round(2), - countries: [CURRENCY_TO_COUNTRY[invoice.amount_currency.to_s]], - currency: invoice.amount_currency.to_s, - merchant_order_id: order.public_id.to_s, - requisite_type: 'card', - idempotency_key: SecureRandom.uuid - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end + + def invoice_params + { + amount_rub: invoice.amount.to_f.round(2), + countries: [CURRENCY_TO_COUNTRY[invoice.amount_currency.to_s]], + currency: invoice.amount_currency.to_s, + merchant_order_id: order.public_id.to_s, + requisite_type: 'card', + idempotency_key: SecureRandom.uuid + } + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/pay_for_u/client.rb b/lib/payment_services/pay_for_u/client.rb index 6e73f1b6..7739711f 100644 --- a/lib/payment_services/pay_for_u/client.rb +++ b/lib/payment_services/pay_for_u/client.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::PayForU - class Client < ::PaymentServices::Base::Client - API_URL = 'https://payforu.cash/public/api/v1' - def initialize(api_key:) - @api_key = api_key - end +module PaymentServices + class PayForU + class Client < ::PaymentServices::Base::Client + API_URL = 'https://payforu.cash/public/api/v1' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/shop/orders", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end + def initialize(api_key:) + @api_key = api_key + end - def transaction(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/shop/orders/#{deposit_id}", - method: :GET, - headers: build_headers - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/shop/orders", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end + + def transaction(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/shop/orders/#{deposit_id}", + method: :GET, + headers: build_headers + ) + end - private + private - attr_reader :api_key + attr_reader :api_key - def build_headers - { - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer #{api_key}" - } + def build_headers + { + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{api_key}" + } + end end end end diff --git a/lib/payment_services/pay_for_u/invoice.rb b/lib/payment_services/pay_for_u/invoice.rb index dd1590c7..a69f880a 100644 --- a/lib/payment_services/pay_for_u/invoice.rb +++ b/lib/payment_services/pay_for_u/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::PayForU - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'completed' - FAILED_PROVIDER_STATE = 'error' - self.table_name = 'pay_for_u_invoices' +module PaymentServices + class PayForU + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'completed' + FAILED_PROVIDER_STATE = 'error' - monetize :amount_cents, as: :amount + self.table_name = 'pay_for_u_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/pay_for_u/invoicer.rb b/lib/payment_services/pay_for_u/invoicer.rb index 332ee2c4..d0fd605d 100644 --- a/lib/payment_services/pay_for_u/invoicer.rb +++ b/lib/payment_services/pay_for_u/invoicer.rb @@ -3,67 +3,70 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::PayForU - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) - invoice.update!( - deposit_id: response['id'], - pay_url: response.dig('integration', 'link') - ) - end +module PaymentServices + class PayForU + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end + invoice.update!( + deposit_id: response['id'], + pay_url: response.dig('integration', 'link') + ) + end - def async_invoice_state_updater? - true - end + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end - def update_invoice_state! - transaction = client.transaction(deposit_id: invoice.deposit_id) - if transaction && amount_matched?(transaction) - invoice.update( - last_4_digits: transaction.dig('payment', 'customerCardLastDigits'), - payment_card_number: transaction.dig('requisites', 'cardInfo') - ) - invoice.update_state_by_provider(transaction['status']) + def async_invoice_state_updater? + true end - end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(deposit_id: invoice.deposit_id) + if transaction && amount_matched?(transaction) + invoice.update( + last_4_digits: transaction.dig('payment', 'customerCardLastDigits'), + payment_card_number: transaction.dig('requisites', 'cardInfo') + ) + invoice.update_state_by_provider(transaction['status']) + end + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - private + private - delegate :income_payment_system, to: :order - delegate :currency, to: :income_payment_system + delegate :income_payment_system, to: :order + delegate :currency, to: :income_payment_system - def invoice_params - { - amount: invoice.amount.to_i, - currency: currency.to_s, - customer: { - id: order.user_id.to_s, - email: order.user_email - }, - integration: { - externalOrderId: order.public_id.to_s, - returnUrl: order.success_redirect + def invoice_params + { + amount: invoice.amount.to_i, + currency: currency.to_s, + customer: { + id: order.user_id.to_s, + email: order.user_email + }, + integration: { + externalOrderId: order.public_id.to_s, + returnUrl: order.success_redirect + } } - } - end + end - def amount_matched?(transaction) - transaction['amount'].to_i == invoice.amount.to_i - end + def amount_matched?(transaction) + transaction['amount'].to_i == invoice.amount.to_i + end - def client - @client ||= Client.new(api_key: api_key) + def client + @client ||= Client.new(api_key: api_key) + end end end end diff --git a/lib/payment_services/pay_for_u_h2h/client.rb b/lib/payment_services/pay_for_u_h2h/client.rb index 03cdc941..4e73c417 100644 --- a/lib/payment_services/pay_for_u_h2h/client.rb +++ b/lib/payment_services/pay_for_u_h2h/client.rb @@ -1,32 +1,35 @@ # frozen_string_literal: true -class PaymentServices::PayForUH2h - class Client < ::PaymentServices::PayForU::Client - def update_invoice(deposit_id:, params:) - safely_parse http_request( - url: "#{API_URL}/shop/orders/#{deposit_id}", - method: :PATCH, - body: params.to_json, - headers: build_headers - ) - end - def start_payment(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/shop/orders/#{deposit_id}/start-payment", - method: :POST, - body: {}.to_json, - headers: build_headers - ) - end +module PaymentServices + class PayForUH2h + class Client < ::PaymentServices::PayForU::Client + def update_invoice(deposit_id:, params:) + safely_parse http_request( + url: "#{API_URL}/shop/orders/#{deposit_id}", + method: :PATCH, + body: params.to_json, + headers: build_headers + ) + end + + def start_payment(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/shop/orders/#{deposit_id}/start-payment", + method: :POST, + body: {}.to_json, + headers: build_headers + ) + end - def confirm_payment(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/shop/orders/#{deposit_id}/confirm-payment", - method: :POST, - body: {}.to_json, - headers: build_headers - ) + def confirm_payment(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/shop/orders/#{deposit_id}/confirm-payment", + method: :POST, + body: {}.to_json, + headers: build_headers + ) + end end end end diff --git a/lib/payment_services/pay_for_u_h2h/invoice.rb b/lib/payment_services/pay_for_u_h2h/invoice.rb index a5165640..40deaa09 100644 --- a/lib/payment_services/pay_for_u_h2h/invoice.rb +++ b/lib/payment_services/pay_for_u_h2h/invoice.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true -class PaymentServices::PayForUH2h - class Invoice < ::PaymentServices::PayForU::Invoice - self.table_name = 'pay_for_u_h2h_invoices' + +module PaymentServices + class PayForUH2h + class Invoice < ::PaymentServices::PayForU::Invoice + self.table_name = 'pay_for_u_h2h_invoices' + end end end diff --git a/lib/payment_services/pay_for_u_h2h/invoicer.rb b/lib/payment_services/pay_for_u_h2h/invoicer.rb index 27eafc1d..026d5aff 100644 --- a/lib/payment_services/pay_for_u_h2h/invoicer.rb +++ b/lib/payment_services/pay_for_u_h2h/invoicer.rb @@ -3,120 +3,123 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::PayForUH2h - class Invoicer < ::PaymentServices::Base::Invoicer - PAYMENT_TYPE = 'card2card' - PROVIDER_REQUISITES_FOUND_STATE = 'customer_confirm' - PROVIDER_REQUEST_RETRIES = 5 - Error = Class.new StandardError - - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - update_provider_invoice_and_start_payment - card_number, card_holder = fetch_card_details! - - PaymentServices::Base::Wallet.new(address: card_number, name: card_holder) - end - def create_invoice(money) - invoice - end +module PaymentServices + class PayForUH2h + class Invoicer < ::PaymentServices::Base::Invoicer + PAYMENT_TYPE = 'card2card' + PROVIDER_REQUISITES_FOUND_STATE = 'customer_confirm' + PROVIDER_REQUEST_RETRIES = 5 + Error = Class.new StandardError - def async_invoice_state_updater? - true - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + update_provider_invoice_and_start_payment + card_number, card_holder = fetch_card_details! - def update_invoice_state! - transaction = client.transaction(deposit_id: invoice.deposit_id) - if valid_transaction?(transaction) - invoice.update( - last_4_digits: transaction.dig('payment', 'customerCardLastDigits'), - payment_card_number: transaction.dig('requisites', 'cardInfo') - ) - invoice.update_state_by_provider(transaction['status']) + PaymentServices::Base::Wallet.new(address: card_number, name: card_holder) end - end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def create_invoice(money) + invoice + end - def confirm_payment - client.confirm_payment(deposit_id: invoice.deposit_id) - end + def async_invoice_state_updater? + true + end - private - - delegate :income_payment_system, :income_account, to: :order - delegate :currency, to: :income_payment_system - - def invoice_params - { - amount: invoice.amount.to_i, - currency: currency.to_s, - customer: { - id: order.user_id.to_s, - email: order.user_email - }, - integration: { - externalOrderId: order.public_id.to_s, - returnUrl: order.success_redirect + def update_invoice_state! + transaction = client.transaction(deposit_id: invoice.deposit_id) + if valid_transaction?(transaction) + invoice.update( + last_4_digits: transaction.dig('payment', 'customerCardLastDigits'), + payment_card_number: transaction.dig('requisites', 'cardInfo') + ) + invoice.update_state_by_provider(transaction['status']) + end + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + def confirm_payment + client.confirm_payment(deposit_id: invoice.deposit_id) + end + + private + + delegate :income_payment_system, :income_account, to: :order + delegate :currency, to: :income_payment_system + + def invoice_params + { + amount: invoice.amount.to_i, + currency: currency.to_s, + customer: { + id: order.user_id.to_s, + email: order.user_email + }, + integration: { + externalOrderId: order.public_id.to_s, + returnUrl: order.success_redirect + } } - } - end + end - def invoice_h2h_params - { - payment: { - bank: provider_bank, - type: PAYMENT_TYPE + def invoice_h2h_params + { + payment: { + bank: provider_bank, + type: PAYMENT_TYPE + } } - } - end + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - deposit_id = client.create_invoice(params: invoice_params).dig('id') - invoice.update!(deposit_id: deposit_id) - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + deposit_id = client.create_invoice(params: invoice_params).dig('id') + invoice.update!(deposit_id: deposit_id) + end - def update_provider_invoice_and_start_payment - update_provider_invoice(params: invoice_h2h_params) - client.start_payment(deposit_id: invoice.deposit_id) - end + def update_provider_invoice_and_start_payment + update_provider_invoice(params: invoice_h2h_params) + client.start_payment(deposit_id: invoice.deposit_id) + end - def update_provider_invoice(params:) - client.update_invoice(deposit_id: invoice.deposit_id, params: params) - end + def update_provider_invoice(params:) + client.update_invoice(deposit_id: invoice.deposit_id, params: params) + end - def fetch_card_details! - transaction = fetch_transaction - raise Error, 'Нет доступных реквизитов для оплаты' if transaction.is_a? Integer + def fetch_card_details! + transaction = fetch_transaction + raise Error, 'Нет доступных реквизитов для оплаты' if transaction.is_a? Integer - card_number, card_holder = transaction.dig('requisites', 'cardInfo'), transaction.dig('requisites', 'cardholder') - update_provider_invoice(params: { payment: { customerCardLastDigits: income_account.last(4) } }) - [card_number, card_holder] - end + card_number, card_holder = transaction.dig('requisites', 'cardInfo'), transaction.dig('requisites', 'cardholder') + update_provider_invoice(params: { payment: { customerCardLastDigits: income_account.last(4) } }) + [card_number, card_holder] + end - def fetch_transaction - PROVIDER_REQUEST_RETRIES.times do - sleep 3 + def fetch_transaction + PROVIDER_REQUEST_RETRIES.times do + sleep 3 - transaction = client.transaction(deposit_id: invoice.deposit_id) - break transaction if transaction['status'] == PROVIDER_REQUISITES_FOUND_STATE + transaction = client.transaction(deposit_id: invoice.deposit_id) + break transaction if transaction['status'] == PROVIDER_REQUISITES_FOUND_STATE + end end - end - def valid_transaction?(transaction) - transaction && transaction['amount'].to_i == invoice.amount.to_i - end + def valid_transaction?(transaction) + transaction && transaction['amount'].to_i == invoice.amount.to_i + end - def provider_bank - @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank - end + def provider_bank + @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank + end - def client - @client ||= Client.new(api_key: api_key) + def client + @client ||= Client.new(api_key: api_key) + end end end end diff --git a/lib/payment_services/paycraft/client.rb b/lib/payment_services/paycraft/client.rb index 50f948b9..63d7cd2c 100644 --- a/lib/payment_services/paycraft/client.rb +++ b/lib/payment_services/paycraft/client.rb @@ -1,63 +1,66 @@ # frozen_string_literal: true -class PaymentServices::Paycraft - class Client < ::PaymentServices::Base::Client - API_URL = 'https://p2p-lk.paycraft.pro/api/proxy/19/transaction/service' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Paycraft + class Client < ::PaymentServices::Base::Client + API_URL = 'https://p2p-lk.paycraft.pro/api/proxy/19/transaction/service' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/create_pay_in", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payin_status", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/create_pay_in", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def create_payout(params:) - safely_parse http_request( - url: "#{API_URL}/create_payout", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payin_status", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def payout(params:) - safely_parse http_request( - url: "#{API_URL}/payout_status", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_payout(params:) + safely_parse http_request( + url: "#{API_URL}/create_payout", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - private + def payout(params:) + safely_parse http_request( + url: "#{API_URL}/payout_status", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - attr_reader :api_key, :secret_key + private - def build_headers(signature:) - { - 'ApiPublic' => api_key, - 'Signature' => signature - } - end + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'ApiPublic' => api_key, + 'Signature' => signature + } + end - def build_signature(params) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) + def build_signature(params) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) + end end end end diff --git a/lib/payment_services/paycraft/invoice.rb b/lib/payment_services/paycraft/invoice.rb index 79d3817c..bc796fa9 100644 --- a/lib/payment_services/paycraft/invoice.rb +++ b/lib/payment_services/paycraft/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Paycraft - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 2 - FAILED_PROVIDER_STATE = 3 - self.table_name = 'paycraft_invoices' +module PaymentServices + class Paycraft + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 2 + FAILED_PROVIDER_STATE = 3 - monetize :amount_cents, as: :amount + self.table_name = 'paycraft_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/paycraft/invoicer.rb b/lib/payment_services/paycraft/invoicer.rb index 87e0be2d..11dbcc9b 100644 --- a/lib/payment_services/paycraft/invoicer.rb +++ b/lib/payment_services/paycraft/invoicer.rb @@ -3,70 +3,73 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Paycraft - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - SBP_PAYWAY = 'СБП' - - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise Error, "Can't create invoice: #{response['description']}" if response['description'].present? - raise Error, "Can't create invoice: #{response['message']}" if response['message'].present? - - invoice.update!(deposit_id: order.public_id.to_s) - PaymentServices::Base::Wallet.new( - address: response['address'], - name: "#{response['surname']} #{response['first_name']}".presence, - memo: response['currency_name'].presence - ) - end - def create_invoice(money) - invoice - end +module PaymentServices + class Paycraft + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + SBP_PAYWAY = 'СБП' - def async_invoice_state_updater? - true - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise Error, "Can't create invoice: #{response['description']}" if response['description'].present? + raise Error, "Can't create invoice: #{response['message']}" if response['message'].present? - def update_invoice_state! - transaction = client.invoice(params: { clientUniqueId: invoice.deposit_id }) - invoice.update(rate: transaction['course'].to_f) - invoice.update_state_by_provider(transaction['status']) if amount_valid?(transaction) - end + invoice.update!(deposit_id: order.public_id.to_s) + PaymentServices::Base::Wallet.new( + address: response['address'], + name: "#{response['surname']} #{response['first_name']}".presence, + memo: response['currency_name'].presence + ) + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def create_invoice(money) + invoice + end - private + def async_invoice_state_updater? + true + end - delegate :card_bank, :sbp?, to: :bank_resolver + def update_invoice_state! + transaction = client.invoice(params: { clientUniqueId: invoice.deposit_id }) + invoice.update(rate: transaction['course'].to_f) + invoice.update_state_by_provider(transaction['status']) if amount_valid?(transaction) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def invoice_params - { - external_id: order.public_id.to_s, - amount: invoice.amount.to_i, - token_name: sbp? ? SBP_PAYWAY : card_bank, - currency: invoice.amount_currency.to_s - } - end + private - def amount_valid?(transaction) - transaction['amountPaid'] == transaction['amount'] || transaction['amountPaid'].zero? - end + delegate :card_bank, :sbp?, to: :bank_resolver - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end + + def invoice_params + { + external_id: order.public_id.to_s, + amount: invoice.amount.to_i, + token_name: sbp? ? SBP_PAYWAY : card_bank, + currency: invoice.amount_currency.to_s + } + end + + def amount_valid?(transaction) + transaction['amountPaid'] == transaction['amount'] || transaction['amountPaid'].zero? + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paycraft/payout.rb b/lib/payment_services/paycraft/payout.rb index 301843de..f9249608 100644 --- a/lib/payment_services/paycraft/payout.rb +++ b/lib/payment_services/paycraft/payout.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Paycraft - class Payout < ::PaymentServices::Base::FiatPayout - SUCCESS_PROVIDER_STATE = 2 - FAILED_PROVIDER_STATE = 3 - self.table_name = 'paycraft_payouts' +module PaymentServices + class Paycraft + class Payout < ::PaymentServices::Base::FiatPayout + SUCCESS_PROVIDER_STATE = 2 + FAILED_PROVIDER_STATE = 3 - monetize :amount_cents, as: :amount + self.table_name = 'paycraft_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/paycraft/payout_adapter.rb b/lib/payment_services/paycraft/payout_adapter.rb index 457c3283..76512922 100644 --- a/lib/payment_services/paycraft/payout_adapter.rb +++ b/lib/payment_services/paycraft/payout_adapter.rb @@ -3,65 +3,68 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Paycraft - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - Error = Class.new StandardError - SBP_PAYWAY = 'СБП' - CARD_PAYWAY = 'Межбанк' - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end +module PaymentServices + class Paycraft + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + Error = Class.new StandardError + SBP_PAYWAY = 'СБП' + CARD_PAYWAY = 'Межбанк' - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - transaction = client.payout(params: { clientUniqueId: payout.withdrawal_id }) - payout.update_state_by_provider(transaction['status']) - transaction - end + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - private + transaction = client.payout(params: { clientUniqueId: payout.withdrawal_id }) + payout.update_state_by_provider(transaction['status']) + transaction + end - delegate :sbp?, :sbp_bank, to: :bank_resolver + private - attr_reader :payout + delegate :sbp?, :sbp_bank, to: :bank_resolver - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise Error, "Can't create payout: #{response['reason']}" if response['reason'].present? + attr_reader :payout - payout.pay!(withdrawal_id: unique_id) - end + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise Error, "Can't create payout: #{response['reason']}" if response['reason'].present? - def unique_id - @unique_id ||= "#{OrderPayout.find(payout.order_payout_id).order.public_id}-#{payout.order_payout_id}" - end + payout.pay!(withdrawal_id: unique_id) + end - def payout_params - { - clientUniqueId: unique_id, - destination: payout.destination_account, - amount: payout.amount.to_i, - walletId: sbp? ? SBP_PAYWAY : CARD_PAYWAY, - expiredTime: 30, - expiredOfferTime: 600, - sbp_bank: sbp? ? sbp_bank : '' - } - end + def unique_id + @unique_id ||= "#{OrderPayout.find(payout.order_payout_id).order.public_id}-#{payout.order_payout_id}" + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def payout_params + { + clientUniqueId: unique_id, + destination: payout.destination_account, + amount: payout.amount.to_i, + walletId: sbp? ? SBP_PAYWAY : CARD_PAYWAY, + expiredTime: 30, + expiredOfferTime: 600, + sbp_bank: sbp? ? sbp_bank : '' + } + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paycraft_virtual/client.rb b/lib/payment_services/paycraft_virtual/client.rb index a2a0fbfa..2f0ff9f2 100644 --- a/lib/payment_services/paycraft_virtual/client.rb +++ b/lib/payment_services/paycraft_virtual/client.rb @@ -1,45 +1,48 @@ # frozen_string_literal: true -class PaymentServices::PaycraftVirtual - class Client < ::PaymentServices::Base::Client - API_URL = 'https://p2p-lk.paycraft.pro/api/proxy/19/transaction/service' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/create_pay_in", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end - - def invoice(params:) - safely_parse http_request( - url: "#{API_URL}/payin_status", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_headers(signature:) - { - 'ApiPublic' => api_key, - 'Signature' => signature - } - end - - def build_signature(params) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) +module PaymentServices + class PaycraftVirtual + class Client < ::PaymentServices::Base::Client + API_URL = 'https://p2p-lk.paycraft.pro/api/proxy/19/transaction/service' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/create_pay_in", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end + + def invoice(params:) + safely_parse http_request( + url: "#{API_URL}/payin_status", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_headers(signature:) + { + 'ApiPublic' => api_key, + 'Signature' => signature + } + end + + def build_signature(params) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) + end end end end diff --git a/lib/payment_services/paycraft_virtual/invoice.rb b/lib/payment_services/paycraft_virtual/invoice.rb index 64b0a5a9..f54f172c 100644 --- a/lib/payment_services/paycraft_virtual/invoice.rb +++ b/lib/payment_services/paycraft_virtual/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::PaycraftVirtual - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 2 - FAILED_PROVIDER_STATE = 3 - self.table_name = 'paycraft_virtual_invoices' +module PaymentServices + class PaycraftVirtual + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 2 + FAILED_PROVIDER_STATE = 3 - monetize :amount_cents, as: :amount + self.table_name = 'paycraft_virtual_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/paycraft_virtual/invoicer.rb b/lib/payment_services/paycraft_virtual/invoicer.rb index 0eea6fad..bbc7aecf 100644 --- a/lib/payment_services/paycraft_virtual/invoicer.rb +++ b/lib/payment_services/paycraft_virtual/invoicer.rb @@ -3,64 +3,67 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::PaycraftVirtual - class Invoicer < ::PaymentServices::Base::Invoicer - Error = Class.new StandardError - PAYWAY = 'Номер счета' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise Error, "Can't create invoice: #{response['description']}" if response['description'].present? - raise Error, "Can't create invoice: #{response['message']}" if response['message'].present? +module PaymentServices + class PaycraftVirtual + class Invoicer < ::PaymentServices::Base::Invoicer + Error = Class.new StandardError + PAYWAY = 'Номер счета' - invoice.update!(deposit_id: order.public_id.to_s) - PaymentServices::Base::Wallet.new( - address: response['address'], - name: "#{response['surname']} #{response['first_name']}".presence, - memo: response['currency_name'].presence - ) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise Error, "Can't create invoice: #{response['description']}" if response['description'].present? + raise Error, "Can't create invoice: #{response['message']}" if response['message'].present? - def create_invoice(money) - invoice - end + invoice.update!(deposit_id: order.public_id.to_s) + PaymentServices::Base::Wallet.new( + address: response['address'], + name: "#{response['surname']} #{response['first_name']}".presence, + memo: response['currency_name'].presence + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.invoice(params: { clientUniqueId: invoice.deposit_id }) - invoice.update(rate: transaction['course'].to_f) - invoice.update_state_by_provider(transaction['status']) if amount_valid?(transaction) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.invoice(params: { clientUniqueId: invoice.deposit_id }) + invoice.update(rate: transaction['course'].to_f) + invoice.update_state_by_provider(transaction['status']) if amount_valid?(transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_params - { - external_id: order.public_id.to_s, - amount: invoice.amount.to_i, - token_name: PAYWAY, - currency: invoice.amount_currency.to_s - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def amount_valid?(transaction) - transaction['amountPaid'] == transaction['amount'] || transaction['amountPaid'].zero? - end + def invoice_params + { + external_id: order.public_id.to_s, + amount: invoice.amount.to_i, + token_name: PAYWAY, + currency: invoice.amount_currency.to_s + } + end + + def amount_valid?(transaction) + transaction['amountPaid'] == transaction['amount'] || transaction['amountPaid'].zero? + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/payeer/client.rb b/lib/payment_services/payeer/client.rb index c4c7a239..a82d10a9 100644 --- a/lib/payment_services/payeer/client.rb +++ b/lib/payment_services/payeer/client.rb @@ -1,95 +1,98 @@ # frozen_string_literal: true -class PaymentServices::Payeer - class Client < ::PaymentServices::Base::Client - API_URL = 'https://payeer.com/ajax/api/api.php' - def initialize(api_id:, api_key:, currency:, account:, secret_key:) - @api_id = api_id - @api_key = api_key - @currency = currency - @account = account - @secret_key = secret_key - end +module PaymentServices + class Payeer + class Client < ::PaymentServices::Base::Client + API_URL = 'https://payeer.com/ajax/api/api.php' - def create_invoice(params:) - safely_parse http_request( - url: API_URL + '?invoiceCreate', - method: :POST, - body: params.merge( - account: account, - apiId: secret_key, - apiPass: api_key, - action: 'invoiceCreate' - ), - headers: build_headers - ) - end + def initialize(api_id:, api_key:, currency:, account:, secret_key:) + @api_id = api_id + @api_key = api_key + @currency = currency + @account = account + @secret_key = secret_key + end - def find_invoice(deposit_id:) - safely_parse http_request( - url: API_URL + '?paymentDetails', - method: :POST, - body: { - account: account, - apiId: secret_key, - apiPass: api_key, - action: 'paymentDetails', - merchantId: api_id, - referenceId: deposit_id - }, - headers: build_headers - ) - end + def create_invoice(params:) + safely_parse http_request( + url: API_URL + '?invoiceCreate', + method: :POST, + body: params.merge( + account: account, + apiId: secret_key, + apiPass: api_key, + action: 'invoiceCreate' + ), + headers: build_headers + ) + end - def create_payout(params:) - safely_parse http_request( - url: API_URL + '?transfer', - method: :POST, - body: params.merge( - apiId: secret_key, - apiPass: api_key, - curIn: currency, - curOut: currency, - action: 'transfer' - ), - headers: build_headers - ) - end + def find_invoice(deposit_id:) + safely_parse http_request( + url: API_URL + '?paymentDetails', + method: :POST, + body: { + account: account, + apiId: secret_key, + apiPass: api_key, + action: 'paymentDetails', + merchantId: api_id, + referenceId: deposit_id + }, + headers: build_headers + ) + end - def payments(params:) - safely_parse http_request( - url: API_URL + '?history', - method: :POST, - body: params.merge( - apiId: secret_key, - apiPass: api_key, - action: 'history' - ), - headers: build_headers - ) - end + def create_payout(params:) + safely_parse http_request( + url: API_URL + '?transfer', + method: :POST, + body: params.merge( + apiId: secret_key, + apiPass: api_key, + curIn: currency, + curOut: currency, + action: 'transfer' + ), + headers: build_headers + ) + end - private + def payments(params:) + safely_parse http_request( + url: API_URL + '?history', + method: :POST, + body: params.merge( + apiId: secret_key, + apiPass: api_key, + action: 'history' + ), + headers: build_headers + ) + end - attr_reader :api_id, :api_key, :currency, :account, :secret_key + private - def build_request(uri:, method:, body: nil, headers:) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, headers) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, headers) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = URI.encode_www_form((body.present? ? body : {})) - request - end + attr_reader :api_id, :api_key, :currency, :account, :secret_key + + def build_request(uri:, method:, body: nil, headers:) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, headers) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, headers) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = URI.encode_www_form((body.present? ? body : {})) + request + end - def build_headers - { - 'content_type' => 'application/x-www-form-urlencoded' - } + def build_headers + { + 'content_type' => 'application/x-www-form-urlencoded' + } + end end end end diff --git a/lib/payment_services/payeer/invoice.rb b/lib/payment_services/payeer/invoice.rb index 805de6da..ecb3f156 100644 --- a/lib/payment_services/payeer/invoice.rb +++ b/lib/payment_services/payeer/invoice.rb @@ -2,17 +2,20 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::Payeer - class Invoice < ::PaymentServices::Base::FiatInvoice - self.table_name = 'payeer_invoices' - monetize :amount_cents, as: :amount +module PaymentServices + class Payeer + class Invoice < ::PaymentServices::Base::FiatInvoice + self.table_name = 'payeer_invoices' - def update_state_by_provider(invoice_transactions) - invoice_transactions_sum = invoice_transactions.sum do |transaction| - transaction['currency'] == amount_currency ? transaction['amount'] : 0 - end - pay! if invoice_transactions_sum == amount.to_f + monetize :amount_cents, as: :amount + + def update_state_by_provider(invoice_transactions) + invoice_transactions_sum = invoice_transactions.sum do |transaction| + transaction['currency'] == amount_currency ? transaction['amount'] : 0 + end + pay! if invoice_transactions_sum == amount.to_f + end end end end diff --git a/lib/payment_services/payeer/invoicer.rb b/lib/payment_services/payeer/invoicer.rb index ca02ffa3..61527b6b 100644 --- a/lib/payment_services/payeer/invoicer.rb +++ b/lib/payment_services/payeer/invoicer.rb @@ -5,49 +5,52 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Payeer - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_invoice(params: invoice_params) - - invoice.update!( - deposit_id: order.public_id.to_s, - pay_url: response['url'] - ) - end - - def pay_invoice_url - invoice.present? ? URI.parse(invoice.reload.pay_url) : '' - end - - def async_invoice_state_updater? - true - end - - def update_invoice_state! - transaction = client.find_invoice(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['items']) - end - - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end - - private - - def client - @client ||= Client.new(api_id: order.income_wallet.merchant_id, api_key: api_key, currency: order.income_wallet.currency.to_s, account: order.income_wallet.num_ps, secret_key: api_secret) - end - def invoice_params - { - m_shop: order.income_wallet.merchant_id, - m_orderid: order.public_id.to_s, - m_amount: invoice.amount.to_d, - m_curr: invoice.amount_currency.to_s, - m_desc: "##{order.public_id}" - } +module PaymentServices + class Payeer + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_invoice(params: invoice_params) + + invoice.update!( + deposit_id: order.public_id.to_s, + pay_url: response['url'] + ) + end + + def pay_invoice_url + invoice.present? ? URI.parse(invoice.reload.pay_url) : '' + end + + def async_invoice_state_updater? + true + end + + def update_invoice_state! + transaction = client.find_invoice(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['items']) + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + private + + def client + @client ||= Client.new(api_id: order.income_wallet.merchant_id, api_key: api_key, currency: order.income_wallet.currency.to_s, account: order.income_wallet.num_ps, secret_key: api_secret) + end + + def invoice_params + { + m_shop: order.income_wallet.merchant_id, + m_orderid: order.public_id.to_s, + m_amount: invoice.amount.to_d, + m_curr: invoice.amount_currency.to_s, + m_desc: "##{order.public_id}" + } + end end end end diff --git a/lib/payment_services/payeer/payout.rb b/lib/payment_services/payeer/payout.rb index 2438720c..d11288a1 100644 --- a/lib/payment_services/payeer/payout.rb +++ b/lib/payment_services/payeer/payout.rb @@ -1,56 +1,59 @@ # frozen_string_literal: true -class PaymentServices::Payeer - class Payout < ApplicationRecord - include Workflow - self.table_name = 'payeer_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed +module PaymentServices + class Payeer + class Payout < ApplicationRecord + include Workflow + + self.table_name = 'payeer_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay - update(reference_id: build_reference_id) - end + def pay + update(reference_id: build_reference_id) + end - def update_provider_state(provider_state) - update!(provider_state: provider_state) + def update_provider_state(provider_state) + update!(provider_state: provider_state) - confirm! if success? - fail! if failed? - end + confirm! if success? + fail! if failed? + end - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) - end + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end - def build_reference_id - "#{order_payout.order.public_id}-#{order_payout.id}" - end + def build_reference_id + "#{order_payout.order.public_id}-#{order_payout.id}" + end - private + private - def success? - provider_state == 'success' - end + def success? + provider_state == 'success' + end - def failed? - provider_state == 'canceled' + def failed? + provider_state == 'canceled' + end end end end diff --git a/lib/payment_services/payeer/payout_adapter.rb b/lib/payment_services/payeer/payout_adapter.rb index 367c9c80..dab93122 100644 --- a/lib/payment_services/payeer/payout_adapter.rb +++ b/lib/payment_services/payeer/payout_adapter.rb @@ -3,55 +3,58 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Payeer - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class Payeer + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - response = client.payments(params: { account: wallet.num_ps }) + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - raise "Can't get withdrawal details: #{response['errors']}" if response['errors'].any? + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - payment = response['history'].values.find do |payment| - payment['referenceId'] == payout.reference_id - end + response = client.payments(params: { account: wallet.num_ps }) - payout.update_provider_state(payment['status']) if payment + raise "Can't get withdrawal details: #{response['errors']}" if response['errors'].any? - payment - end + payment = response['history'].values.find do |payment| + payment['referenceId'] == payout.reference_id + end + + payout.update_provider_state(payment['status']) if payment - private + payment + end - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + private - params = { - account: wallet.num_ps, - sumOut: amount.to_d, - to: destination_account, - comment: "Перевод по заявке №#{payout.order_payout.order.public_id} на сайте Kassa.cc", - referenceId: payout.build_reference_id - } - response = client.create_payout(params: params) + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - raise "Can't process payout: #{response['errors']}" if response['errors'].is_a? Array + params = { + account: wallet.num_ps, + sumOut: amount.to_d, + to: destination_account, + comment: "Перевод по заявке №#{payout.order_payout.order.public_id} на сайте Kassa.cc", + referenceId: payout.build_reference_id + } + response = client.create_payout(params: params) - payout.pay! - end + raise "Can't process payout: #{response['errors']}" if response['errors'].is_a? Array - def client - @client ||= Client.new(api_id: wallet.merchant_id, api_key: api_key, currency: wallet.currency.to_s, account: wallet.num_ps, secret_key: api_secret) + payout.pay! + end + + def client + @client ||= Client.new(api_id: wallet.merchant_id, api_key: api_key, currency: wallet.currency.to_s, account: wallet.num_ps, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paylama/client.rb b/lib/payment_services/paylama/client.rb index 07dc8cae..d43de916 100644 --- a/lib/payment_services/paylama/client.rb +++ b/lib/payment_services/paylama/client.rb @@ -1,89 +1,92 @@ # frozen_string_literal: true -class PaymentServices::Paylama - class Client < ::PaymentServices::Base::Client - FIAT_API_URL = 'https://admin.paylama.io/api/api/payment' - CRYPTO_API_URL = 'https://admin.paylama.io/api/crypto' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Paylama + class Client < ::PaymentServices::Base::Client + FIAT_API_URL = 'https://admin.paylama.io/api/api/payment' + CRYPTO_API_URL = 'https://admin.paylama.io/api/crypto' - def create_fiat_invoice(params:) - safely_parse http_request( - url: "#{FIAT_API_URL}/generate_invoice_h2h", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def process_fiat_payout(params:) - safely_parse http_request( - url: "#{FIAT_API_URL}/generate_withdraw", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_fiat_invoice(params:) + safely_parse http_request( + url: "#{FIAT_API_URL}/generate_invoice_h2h", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def create_p2p_invoice(params:) - safely_parse http_request( - url: "#{FIAT_API_URL}/generate_invoice_card_transfer", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def process_fiat_payout(params:) + safely_parse http_request( + url: "#{FIAT_API_URL}/generate_withdraw", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def create_crypto_address(currency:) - params = { currency: currency } - safely_parse http_request( - url: "#{CRYPTO_API_URL}/payment", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_p2p_invoice(params:) + safely_parse http_request( + url: "#{FIAT_API_URL}/generate_invoice_card_transfer", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def process_crypto_payout(params:) - safely_parse http_request( - url: "#{CRYPTO_API_URL}/payout", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def create_crypto_address(currency:) + params = { currency: currency } + safely_parse http_request( + url: "#{CRYPTO_API_URL}/payment", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - def payment_status(payment_id:, type:) - params = { - externalID: payment_id, - orderType: type - } + def process_crypto_payout(params:) + safely_parse http_request( + url: "#{CRYPTO_API_URL}/payout", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - safely_parse http_request( - url: "#{FIAT_API_URL}/get_order_details", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) - end + def payment_status(payment_id:, type:) + params = { + externalID: payment_id, + orderType: type + } - private + safely_parse http_request( + url: "#{FIAT_API_URL}/get_order_details", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end - attr_reader :api_key, :secret_key + private - def build_signature(params) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) - end + attr_reader :api_key, :secret_key + + def build_signature(params) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, params.to_json) + end - def build_headers(signature:) - { - 'Content-Type' => 'application/json', - 'API-Key' => api_key, - 'Signature' => signature - } + def build_headers(signature:) + { + 'Content-Type' => 'application/json', + 'API-Key' => api_key, + 'Signature' => signature + } + end end end end diff --git a/lib/payment_services/paylama/currency_repository.rb b/lib/payment_services/paylama/currency_repository.rb index 83efdb20..4aceefe0 100644 --- a/lib/payment_services/paylama/currency_repository.rb +++ b/lib/payment_services/paylama/currency_repository.rb @@ -1,46 +1,49 @@ # frozen_string_literal: true -class PaymentServices::Paylama - class CurrencyRepository - CURRENCY_TO_PROVIDER_CURRENCY = { RUB: 1, USD: 2, KZT: 3, EUR: 4, UZS: 36, AZN: 37, DSH: 'DASH' }.stringify_keys.freeze - TOKEN_NETWORK_TO_PROVIDER_CURRENCY = { erc20: 'USDT', trc20: 'USDTTRC', bep20: 'USDTBEP', bep2: 'BNB' }.stringify_keys.freeze - TOKEN_NETWORK_TO_GETBLOCK_CURRENCY = { erc20: 'USDTERC20', trc20: 'USDTTRC20' }.stringify_keys.freeze - BNB_BEP20_PROVIDER_CURRENCY = 'BNB20' - BNB_BEP20_TOKEN_NETWORK = 'bep20' - - include Virtus.model - - attribute :kassa_currency, String - attribute :token_network, String - - def self.build_from(kassa_currency:, token_network: nil) - new( - kassa_currency: kassa_currency.to_s, - token_network: token_network - ) - end - def fiat_currency_id - CURRENCY_TO_PROVIDER_CURRENCY[kassa_currency] - end +module PaymentServices + class Paylama + class CurrencyRepository + CURRENCY_TO_PROVIDER_CURRENCY = { RUB: 1, USD: 2, KZT: 3, EUR: 4, UZS: 36, AZN: 37, DSH: 'DASH' }.stringify_keys.freeze + TOKEN_NETWORK_TO_PROVIDER_CURRENCY = { erc20: 'USDT', trc20: 'USDTTRC', bep20: 'USDTBEP', bep2: 'BNB' }.stringify_keys.freeze + TOKEN_NETWORK_TO_GETBLOCK_CURRENCY = { erc20: 'USDTERC20', trc20: 'USDTTRC20' }.stringify_keys.freeze + BNB_BEP20_PROVIDER_CURRENCY = 'BNB20' + BNB_BEP20_TOKEN_NETWORK = 'bep20' - def provider_crypto_currency - return BNB_BEP20_PROVIDER_CURRENCY if bnb_bep20? - return TOKEN_NETWORK_TO_PROVIDER_CURRENCY[token_network] if token_network.present? + include Virtus.model - CURRENCY_TO_PROVIDER_CURRENCY[kassa_currency] || kassa_currency - end + attribute :kassa_currency, String + attribute :token_network, String - def getblock_currency - return TOKEN_NETWORK_TO_GETBLOCK_CURRENCY[token_network] if token_network.present? + def self.build_from(kassa_currency:, token_network: nil) + new( + kassa_currency: kassa_currency.to_s, + token_network: token_network + ) + end - CURRENCY_TO_PROVIDER_CURRENCY[kassa_currency] || kassa_currency - end + def fiat_currency_id + CURRENCY_TO_PROVIDER_CURRENCY[kassa_currency] + end + + def provider_crypto_currency + return BNB_BEP20_PROVIDER_CURRENCY if bnb_bep20? + return TOKEN_NETWORK_TO_PROVIDER_CURRENCY[token_network] if token_network.present? + + CURRENCY_TO_PROVIDER_CURRENCY[kassa_currency] || kassa_currency + end + + def getblock_currency + return TOKEN_NETWORK_TO_GETBLOCK_CURRENCY[token_network] if token_network.present? + + CURRENCY_TO_PROVIDER_CURRENCY[kassa_currency] || kassa_currency + end - private + private - def bnb_bep20? - kassa_currency.inquiry.BNB? && token_network == BNB_BEP20_TOKEN_NETWORK + def bnb_bep20? + kassa_currency.inquiry.BNB? && token_network == BNB_BEP20_TOKEN_NETWORK + end end end end diff --git a/lib/payment_services/paylama/invoice.rb b/lib/payment_services/paylama/invoice.rb index ac0e548f..59d4c44e 100644 --- a/lib/payment_services/paylama/invoice.rb +++ b/lib/payment_services/paylama/invoice.rb @@ -1,54 +1,57 @@ # frozen_string_literal: true -class PaymentServices::Paylama - class Invoice < ApplicationRecord - SUCCESS_PROVIDER_STATE = 'Succeed' - FAILED_PROVIDER_STATE = 'Failed' - include Workflow +module PaymentServices + class Paylama + class Invoice < ApplicationRecord + SUCCESS_PROVIDER_STATE = 'Succeed' + FAILED_PROVIDER_STATE = 'Failed' - self.table_name = 'paylama_invoices' + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'paylama_invoices' - monetize :amount_cents, as: :amount + scope :ordered, -> { order(id: :desc) } - validates :amount_cents, :order_public_id, :state, presence: true + monetize :amount_cents, as: :amount - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount, hash: deposit_id) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount, hash: deposit_id) + end end + state :cancelled end - state :cancelled - end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - pay! if provider_succeed? - cancel! if provider_failed? - end + pay! if provider_succeed? + cancel! if provider_failed? + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - private + private - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/paylama/invoicer.rb b/lib/payment_services/paylama/invoicer.rb index 26d9d91c..a8216eb6 100644 --- a/lib/payment_services/paylama/invoicer.rb +++ b/lib/payment_services/paylama/invoicer.rb @@ -4,76 +4,79 @@ require_relative 'client' require_relative 'currency_repository' -class PaymentServices::Paylama - class Invoicer < ::PaymentServices::Base::Invoicer - P2P_BANK_NAME = 'tinkoff' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - response = client.create_p2p_invoice(params: invoice_p2p_params) - PaymentServices::Base::Wallet.new(address: response['cardNumber'], name: response['cardHolderName']) - end +module PaymentServices + class Paylama + class Invoicer < ::PaymentServices::Base::Invoicer + P2P_BANK_NAME = 'tinkoff' - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - response = client.create_fiat_invoice(params: invoice_params) - raise "Can't create invoice: #{response['cause']}" unless response['success'] + def prepare_invoice_and_get_wallet!(currency:, token_network:) + response = client.create_p2p_invoice(params: invoice_p2p_params) + PaymentServices::Base::Wallet.new(address: response['cardNumber'], name: response['cardHolderName']) + end - invoice.update!( - deposit_id: response['billID'], - pay_url: response['paymentURL'] - ) - end + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + response = client.create_fiat_invoice(params: invoice_params) + raise "Can't create invoice: #{response['cause']}" unless response['success'] - def pay_invoice_url - (invoice.present? && invoice.reload.pay_url.present?) ? URI.parse(invoice.pay_url) : '' - end + invoice.update!( + deposit_id: response['billID'], + pay_url: response['paymentURL'] + ) + end - def async_invoice_state_updater? - true - end + def pay_invoice_url + (invoice.present? && invoice.reload.pay_url.present?) ? URI.parse(invoice.pay_url) : '' + end - def update_invoice_state! - response = client.payment_status(payment_id: invoice.deposit_id, type: 'invoice') - raise 'Empty paylama response' unless response&.dig('ID') + def async_invoice_state_updater? + true + end - invoice.update_state_by_provider(response['status']) - end + def update_invoice_state! + response = client.payment_status(payment_id: invoice.deposit_id, type: 'invoice') + raise 'Empty paylama response' unless response&.dig('ID') - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update_state_by_provider(response['status']) + end - private - - def invoice_params - { - amount: invoice.amount.to_i, - expireAt: order.income_payment_timeout, - comment: order.public_id.to_s, - clientIP: order.remote_ip || '', - currencyID: invoice_fiat_currency_id, - redirect: { - successURL: order.success_redirect, - failURL: order.failed_redirect + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end + + private + + def invoice_params + { + amount: invoice.amount.to_i, + expireAt: order.income_payment_timeout, + comment: order.public_id.to_s, + clientIP: order.remote_ip || '', + currencyID: invoice_fiat_currency_id, + redirect: { + successURL: order.success_redirect, + failURL: order.failed_redirect + } } - } - end + end - def invoice_p2p_params - { - bankName: P2P_BANK_NAME, - amount: order.income_money.to_i, - comment: order.public_id.to_s, - currencyID: invoice_fiat_currency_id - } - end + def invoice_p2p_params + { + bankName: P2P_BANK_NAME, + amount: order.income_money.to_i, + comment: order.public_id.to_s, + currencyID: invoice_fiat_currency_id + } + end - def invoice_fiat_currency_id - @invoice_fiat_currency_id ||= CurrencyRepository.build_from(kassa_currency: order.income_payment_system.currency).fiat_currency_id - end + def invoice_fiat_currency_id + @invoice_fiat_currency_id ||= CurrencyRepository.build_from(kassa_currency: order.income_payment_system.currency).fiat_currency_id + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paylama/payout.rb b/lib/payment_services/paylama/payout.rb index 3ce3c396..93ff1703 100644 --- a/lib/payment_services/paylama/payout.rb +++ b/lib/payment_services/paylama/payout.rb @@ -1,51 +1,54 @@ # frozen_string_literal: true -class PaymentServices::Paylama - class Payout < ApplicationRecord - SUCCESS_PROVIDER_STATE = 'Succeed' - FAILED_PROVIDER_STATE = 'Failed' - include Workflow +module PaymentServices + class Paylama + class Payout < ApplicationRecord + SUCCESS_PROVIDER_STATE = 'Succeed' + FAILED_PROVIDER_STATE = 'Failed' - self.table_name = 'paylama_payouts' + include Workflow - scope :ordered, -> { order(id: :desc) } + self.table_name = 'paylama_payouts' - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, :order_payout_id, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, :order_payout_id, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :completed - state :failed - end - def pay(withdrawal_id:) - update(withdrawal_id: withdrawal_id) - end + def pay(withdrawal_id:) + update(withdrawal_id: withdrawal_id) + end - def update_state_by_provider(state) - update!(provider_state: state) + def update_state_by_provider(state) + update!(provider_state: state) - confirm! if provider_succeed? - fail! if provider_failed? - end + confirm! if provider_succeed? + fail! if provider_failed? + end - private + private - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/paylama/payout_adapter.rb b/lib/payment_services/paylama/payout_adapter.rb index 466a4b68..ae486888 100644 --- a/lib/payment_services/paylama/payout_adapter.rb +++ b/lib/payment_services/paylama/payout_adapter.rb @@ -4,67 +4,70 @@ require_relative 'client' require_relative 'currency_repository' -class PaymentServices::Paylama - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - PAYOUT_TIME_ALIVE = 1800.seconds - PAYSOURCE_OPTIONS = { - 'visamc' => 'card', - 'cardh2h' => 'card', - 'qiwi' => 'qw', - 'qiwih2h' => 'qw' - } - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end +module PaymentServices + class Paylama + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + PAYOUT_TIME_ALIVE = 1800.seconds + PAYSOURCE_OPTIONS = { + 'visamc' => 'card', + 'cardh2h' => 'card', + 'qiwi' => 'qw', + 'qiwih2h' => 'qw' + } - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.payment_status(payment_id: payout.withdrawal_id, type: 'withdraw') - raise "Can't get payment information: #{response}" unless response['ID'] + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - payout.update_state_by_provider(response['status']) - response - end + response = client.payment_status(payment_id: payout.withdrawal_id, type: 'withdraw') + raise "Can't get payment information: #{response}" unless response['ID'] - private + payout.update_state_by_provider(response['status']) + response + end - attr_reader :payout - delegate :outcome_api_key, :outcome_api_secret, to: :wallet + private - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.process_fiat_payout(params: payout_params) - raise "Can't create payout: #{response}" unless response['success'] + attr_reader :payout + delegate :outcome_api_key, :outcome_api_secret, to: :wallet - payout.pay!(withdrawal_id: response['billID']) - end + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.process_fiat_payout(params: payout_params) + raise "Can't create payout: #{response}" unless response['success'] - def payout_params - order = OrderPayout.find(payout.order_payout_id).order - { - amount: payout.amount.to_i, - expireAt: PAYOUT_TIME_ALIVE.to_i, - comment: "#{order.public_id}-#{payout.order_payout_id}", - clientIP: order.remote_ip || '', - paySourcesFilter: pay_source, - currencyID: CurrencyRepository.build_from(kassa_currency: wallet.currency).fiat_currency_id, - recipient: payout.destination_account - } - end + payout.pay!(withdrawal_id: response['billID']) + end - def pay_source - PAYSOURCE_OPTIONS[wallet.payment_system.payway] - end + def payout_params + order = OrderPayout.find(payout.order_payout_id).order + { + amount: payout.amount.to_i, + expireAt: PAYOUT_TIME_ALIVE.to_i, + comment: "#{order.public_id}-#{payout.order_payout_id}", + clientIP: order.remote_ip || '', + paySourcesFilter: pay_source, + currencyID: CurrencyRepository.build_from(kassa_currency: wallet.currency).fiat_currency_id, + recipient: payout.destination_account + } + end + + def pay_source + PAYSOURCE_OPTIONS[wallet.payment_system.payway] + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paylama_crypto/invoice.rb b/lib/payment_services/paylama_crypto/invoice.rb index 2b30e3dd..6291f551 100644 --- a/lib/payment_services/paylama_crypto/invoice.rb +++ b/lib/payment_services/paylama_crypto/invoice.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::PaylamaCrypto - class Invoice < ::PaymentServices::Base::CryptoInvoice - self.table_name = 'paylama_invoices' - - monetize :amount_cents, as: :amount - - def update_state_by_transaction(transaction) - validate_transaction_amount(transaction: transaction) - bind_transaction! if pending? - update!( - provider_state: transaction.status, - transaction_created_at: transaction.created_at, - fee: transaction.fee - ) - - pay!(payload: transaction) if transaction.succeed? - cancel! if transaction.failed? - end - def transaction_id - order.income_wallet.name - end +module PaymentServices + class PaylamaCrypto + class Invoice < ::PaymentServices::Base::CryptoInvoice + self.table_name = 'paylama_invoices' - private + monetize :amount_cents, as: :amount - delegate :income_payment_system, to: :order - delegate :token_network, to: :income_payment_system + def update_state_by_transaction(transaction) + validate_transaction_amount(transaction: transaction) + bind_transaction! if pending? + update!( + provider_state: transaction.status, + transaction_created_at: transaction.created_at, + fee: transaction.fee + ) - def validate_transaction_amount(transaction:) - raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_provider_currency) - end + pay!(payload: transaction) if transaction.succeed? + cancel! if transaction.failed? + end + + def transaction_id + order.income_wallet.name + end + + private + + delegate :income_payment_system, to: :order + delegate :token_network, to: :income_payment_system + + def validate_transaction_amount(transaction:) + raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + end - def amount_provider_currency - @amount_provider_currency ||= PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: amount_currency, token_network: token_network).provider_crypto_currency + def amount_provider_currency + @amount_provider_currency ||= PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: amount_currency, token_network: token_network).provider_crypto_currency + end end end end diff --git a/lib/payment_services/paylama_crypto/invoicer.rb b/lib/payment_services/paylama_crypto/invoicer.rb index b4ce53b6..ccfae229 100644 --- a/lib/payment_services/paylama_crypto/invoicer.rb +++ b/lib/payment_services/paylama_crypto/invoicer.rb @@ -3,40 +3,43 @@ require_relative 'invoice' require_relative 'transaction' -class PaymentServices::PaylamaCrypto - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end - def prepare_invoice_and_get_wallet!(currency:, token_network:) - provider_crypto_currency = PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: currency, token_network: token_network).provider_crypto_currency - response = client.create_crypto_address(currency: provider_crypto_currency) - raise "Can't create crypto address: #{response['cause']}" unless response['id'] +module PaymentServices + class PaylamaCrypto + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - PaymentServices::Base::Wallet.new(address: response['address'], name: response['id']) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + provider_crypto_currency = PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: currency, token_network: token_network).provider_crypto_currency + response = client.create_crypto_address(currency: provider_crypto_currency) + raise "Can't create crypto address: #{response['cause']}" unless response['id'] - def async_invoice_state_updater? - true - end + PaymentServices::Base::Wallet.new(address: response['address'], name: response['id']) + end - def update_invoice_state! - raw_transaction = client.payment_status(payment_id: order.income_wallet.name, type: 'invoice') - raise "Can't get payment information: #{raw_transaction['cause']}" unless raw_transaction['ID'] + def async_invoice_state_updater? + true + end - transaction = Transaction.build_from(raw_transaction) - invoice.update_state_by_transaction(transaction) - end + def update_invoice_state! + raw_transaction = client.payment_status(payment_id: order.income_wallet.name, type: 'invoice') + raise "Can't get payment information: #{raw_transaction['cause']}" unless raw_transaction['ID'] - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + transaction = Transaction.build_from(raw_transaction) + invoice.update_state_by_transaction(transaction) + end + + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - private + private - def client - @client ||= PaymentServices::Paylama::Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= PaymentServices::Paylama::Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paylama_crypto/payout.rb b/lib/payment_services/paylama_crypto/payout.rb index db7ae5ac..9d484ced 100644 --- a/lib/payment_services/paylama_crypto/payout.rb +++ b/lib/payment_services/paylama_crypto/payout.rb @@ -1,15 +1,18 @@ # frozen_string_literal: true -class PaymentServices::PaylamaCrypto - class Payout < ::PaymentServices::Paylama::Payout - def update_state_by_transaction(transaction) - update!( - provider_state: transaction.status, - fee: transaction.fee - ) - confirm! if transaction.succeed? - fail! if transaction.failed? +module PaymentServices + class PaylamaCrypto + class Payout < ::PaymentServices::Paylama::Payout + def update_state_by_transaction(transaction) + update!( + provider_state: transaction.status, + fee: transaction.fee + ) + + confirm! if transaction.succeed? + fail! if transaction.failed? + end end end end diff --git a/lib/payment_services/paylama_crypto/payout_adapter.rb b/lib/payment_services/paylama_crypto/payout_adapter.rb index e38175c7..50b307fe 100644 --- a/lib/payment_services/paylama_crypto/payout_adapter.rb +++ b/lib/payment_services/paylama_crypto/payout_adapter.rb @@ -3,54 +3,57 @@ require_relative 'payout' require_relative 'transaction' -class PaymentServices::PaylamaCrypto - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? - - raw_transaction = client.payment_status(payment_id: payout.withdrawal_id, type: 'withdraw') - raise "Can't get payment information: #{raw_transaction}" unless raw_transaction['ID'] - - transaction = Transaction.build_from(raw_transaction) - payout.update_state_by_transaction(transaction) - raw_transaction - end - - private - - attr_reader :payout - - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.process_crypto_payout(params: payout_params) - raise "Can't create payout: #{response}" unless response['ID'] - - payout.pay!(withdrawal_id: response['ID']) - end - - def payout_params - { - amount: payout.amount.to_f, - currency: currency, - address: payout.destination_account - } - end - - def currency - @currency ||= PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: wallet.currency, token_network: wallet.payment_system.token_network).provider_crypto_currency - end - def client - @client ||= PaymentServices::Paylama::Client.new(api_key: api_key, secret_key: api_secret) +module PaymentServices + class PaylamaCrypto + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end + + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? + + raw_transaction = client.payment_status(payment_id: payout.withdrawal_id, type: 'withdraw') + raise "Can't get payment information: #{raw_transaction}" unless raw_transaction['ID'] + + transaction = Transaction.build_from(raw_transaction) + payout.update_state_by_transaction(transaction) + raw_transaction + end + + private + + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.process_crypto_payout(params: payout_params) + raise "Can't create payout: #{response}" unless response['ID'] + + payout.pay!(withdrawal_id: response['ID']) + end + + def payout_params + { + amount: payout.amount.to_f, + currency: currency, + address: payout.destination_account + } + end + + def currency + @currency ||= PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: wallet.currency, token_network: wallet.payment_system.token_network).provider_crypto_currency + end + + def client + @client ||= PaymentServices::Paylama::Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paylama_crypto/transaction.rb b/lib/payment_services/paylama_crypto/transaction.rb index 801ff02c..4e36d876 100644 --- a/lib/payment_services/paylama_crypto/transaction.rb +++ b/lib/payment_services/paylama_crypto/transaction.rb @@ -1,56 +1,59 @@ # frozen_string_literal: true -class PaymentServices::PaylamaCrypto - class Transaction - SUCCESS_TRANSACTION_STATE = 'Succeed' - FAILED_TRANSACTION_STATE = 'Failed' - - include Virtus.model - - attribute :amount, Float - attribute :currency, String - attribute :status, String - attribute :fee, Float - attribute :created_at, DateTime - attribute :source, Hash - - def self.build_from(raw_transaction) - new( - amount: raw_transaction['amount'].to_f, - currency: raw_transaction['currency'], - status: raw_transaction['status'], - fee: raw_transaction['fee'], - created_at: DateTime.strptime(raw_transaction['createdAt'].to_s,'%s').utc, - source: raw_transaction - ) - end - - def to_s - source.to_s - end - - def valid_amount?(payout_amount, payout_currency) - (amount == 0 || amount == payout_amount) && currency == payout_currency - end - - def succeed? - send("#{currency}_transaction_succeed?") - end - - def failed? - status == FAILED_TRANSACTION_STATE - end - - private - - def method_missing(method_name) - super unless method_name.end_with?('_transaction_succeed?') - - default_transaction_succeed? - end - def default_transaction_succeed? - status == SUCCESS_TRANSACTION_STATE +module PaymentServices + class PaylamaCrypto + class Transaction + SUCCESS_TRANSACTION_STATE = 'Succeed' + FAILED_TRANSACTION_STATE = 'Failed' + + include Virtus.model + + attribute :amount, Float + attribute :currency, String + attribute :status, String + attribute :fee, Float + attribute :created_at, DateTime + attribute :source, Hash + + def self.build_from(raw_transaction) + new( + amount: raw_transaction['amount'].to_f, + currency: raw_transaction['currency'], + status: raw_transaction['status'], + fee: raw_transaction['fee'], + created_at: DateTime.strptime(raw_transaction['createdAt'].to_s,'%s').utc, + source: raw_transaction + ) + end + + def to_s + source.to_s + end + + def valid_amount?(payout_amount, payout_currency) + (amount == 0 || amount == payout_amount) && currency == payout_currency + end + + def succeed? + send("#{currency}_transaction_succeed?") + end + + def failed? + status == FAILED_TRANSACTION_STATE + end + + private + + def method_missing(method_name) + super unless method_name.end_with?('_transaction_succeed?') + + default_transaction_succeed? + end + + def default_transaction_succeed? + status == SUCCESS_TRANSACTION_STATE + end end end end diff --git a/lib/payment_services/paylama_p2p/client.rb b/lib/payment_services/paylama_p2p/client.rb index f4262826..c10ab28f 100644 --- a/lib/payment_services/paylama_p2p/client.rb +++ b/lib/payment_services/paylama_p2p/client.rb @@ -1,14 +1,17 @@ # frozen_string_literal: true -class PaymentServices::PaylamaP2p - class Client < ::PaymentServices::Paylama::Client - def create_provider_invoice(params:) - safely_parse http_request( - url: "#{FIAT_API_URL}/generate_invoice_card_transfer", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) + +module PaymentServices + class PaylamaP2p + class Client < ::PaymentServices::Paylama::Client + def create_provider_invoice(params:) + safely_parse http_request( + url: "#{FIAT_API_URL}/generate_invoice_card_transfer", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end end end end diff --git a/lib/payment_services/paylama_p2p/invoice.rb b/lib/payment_services/paylama_p2p/invoice.rb index 55f91e08..d6c075b8 100644 --- a/lib/payment_services/paylama_p2p/invoice.rb +++ b/lib/payment_services/paylama_p2p/invoice.rb @@ -1,7 +1,10 @@ # frozen_string_literal: true -class PaymentServices::PaylamaP2p - class Invoice < ::PaymentServices::PaylamaSbp::Invoice - self.table_name = 'paylama_p2p_invoices' + +module PaymentServices + class PaylamaP2p + class Invoice < ::PaymentServices::PaylamaSbp::Invoice + self.table_name = 'paylama_p2p_invoices' + end end end diff --git a/lib/payment_services/paylama_p2p/invoicer.rb b/lib/payment_services/paylama_p2p/invoicer.rb index 6fb58785..32156ce7 100644 --- a/lib/payment_services/paylama_p2p/invoicer.rb +++ b/lib/payment_services/paylama_p2p/invoicer.rb @@ -3,72 +3,75 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::PaylamaP2p - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_provider_invoice(params: invoice_p2p_params) - raise response['cause'] unless response['success'] - - invoice.update!(deposit_id: response['externalId']) - PaymentServices::Base::Wallet.new( - address: response['cardNumber'], - name: response['cardHolderName'], - memo: PROVIDER_BANK_NAME.capitalize - ) - end - def create_invoice(money) - invoice - end +module PaymentServices + class PaylamaP2p + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_provider_invoice(params: invoice_p2p_params) + raise response['cause'] unless response['success'] - def async_invoice_state_updater? - true - end + invoice.update!(deposit_id: response['externalId']) + PaymentServices::Base::Wallet.new( + address: response['cardNumber'], + name: response['cardHolderName'], + memo: PROVIDER_BANK_NAME.capitalize + ) + end - def update_invoice_state! - transaction = client.payment_status(payment_id: invoice.deposit_id, type: 'invoice') - invoice.update_state_by_provider(transaction['status']) if valid_transaction?(transaction) - end + def create_invoice(money) + invoice + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def async_invoice_state_updater? + true + end - private + def update_invoice_state! + transaction = client.payment_status(payment_id: invoice.deposit_id, type: 'invoice') + invoice.update_state_by_provider(transaction['status']) if valid_transaction?(transaction) + end - delegate :income_payment_system, to: :order + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_p2p_params - { - clientOrderID: order.public_id.to_s, - payerID: "#{Rails.env}_user_id_#{order.user_id}", - amount: invoice.amount.to_i, - bankName: provider_bank, - comment: "Order #{order.public_id}", - currencyID: currency_id, - expireAt: order.income_payment_timeout - } - end + delegate :income_payment_system, to: :order - def valid_transaction?(transaction) - transaction && transaction['amount'].to_i == invoice.amount.to_i - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def provider_bank - @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank - end + def invoice_p2p_params + { + clientOrderID: order.public_id.to_s, + payerID: "#{Rails.env}_user_id_#{order.user_id}", + amount: invoice.amount.to_i, + bankName: provider_bank, + comment: "Order #{order.public_id}", + currencyID: currency_id, + expireAt: order.income_payment_timeout + } + end - def currency_id - @currency_id ||= Paylama::CurrencyRepository.build_from(kassa_currency: order.income_payment_system.currency).fiat_currency_id - end + def valid_transaction?(transaction) + transaction && transaction['amount'].to_i == invoice.amount.to_i + end + + def provider_bank + @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank + end + + def currency_id + @currency_id ||= Paylama::CurrencyRepository.build_from(kassa_currency: order.income_payment_system.currency).fiat_currency_id + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/paylama_sbp/client.rb b/lib/payment_services/paylama_sbp/client.rb index 8457e040..9535d157 100644 --- a/lib/payment_services/paylama_sbp/client.rb +++ b/lib/payment_services/paylama_sbp/client.rb @@ -1,14 +1,17 @@ # frozen_string_literal: true -class PaymentServices::PaylamaSbp - class Client < ::PaymentServices::Paylama::Client - def create_provider_invoice(params:) - safely_parse http_request( - url: "#{FIAT_API_URL}/generate_invoice_fps_h2h", - method: :POST, - body: params.to_json, - headers: build_headers(signature: build_signature(params)) - ) + +module PaymentServices + class PaylamaSbp + class Client < ::PaymentServices::Paylama::Client + def create_provider_invoice(params:) + safely_parse http_request( + url: "#{FIAT_API_URL}/generate_invoice_fps_h2h", + method: :POST, + body: params.to_json, + headers: build_headers(signature: build_signature(params)) + ) + end end end end diff --git a/lib/payment_services/paylama_sbp/invoice.rb b/lib/payment_services/paylama_sbp/invoice.rb index 5cc84a37..a781dc41 100644 --- a/lib/payment_services/paylama_sbp/invoice.rb +++ b/lib/payment_services/paylama_sbp/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::PaylamaSbp - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'Succeed' - FAILED_PROVIDER_STATE = 'Failed' - self.table_name = 'paylama_sbp_invoices' +module PaymentServices + class PaylamaSbp + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'Succeed' + FAILED_PROVIDER_STATE = 'Failed' - monetize :amount_cents, as: :amount + self.table_name = 'paylama_sbp_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/paylama_sbp/invoicer.rb b/lib/payment_services/paylama_sbp/invoicer.rb index a2675e0d..d4918151 100644 --- a/lib/payment_services/paylama_sbp/invoicer.rb +++ b/lib/payment_services/paylama_sbp/invoicer.rb @@ -3,70 +3,73 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::PaylamaSbp - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_provider_invoice(params: invoice_fps_params) - raise response['cause'] unless response['success'] - - invoice.update!(deposit_id: response['externalID']) - PaymentServices::Base::Wallet.new( - address: prepare_phone_number(response['phoneNumber']), - name: response['cardHolderName'], - memo: response['bankName'].capitalize - ) - end - def create_invoice(money) - invoice - end +module PaymentServices + class PaylamaSbp + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_provider_invoice(params: invoice_fps_params) + raise response['cause'] unless response['success'] - def async_invoice_state_updater? - true - end + invoice.update!(deposit_id: response['externalID']) + PaymentServices::Base::Wallet.new( + address: prepare_phone_number(response['phoneNumber']), + name: response['cardHolderName'], + memo: response['bankName'].capitalize + ) + end - def update_invoice_state! - transaction = client.payment_status(payment_id: invoice.deposit_id, type: 'invoice') - invoice.update_state_by_provider(transaction['status']) if valid_transaction?(transaction) - end + def create_invoice(money) + invoice + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def async_invoice_state_updater? + true + end - private + def update_invoice_state! + transaction = client.payment_status(payment_id: invoice.deposit_id, type: 'invoice') + invoice.update_state_by_provider(transaction['status']) if valid_transaction?(transaction) + end - delegate :income_payment_system, to: :order + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_fps_params - { - payerID: "#{Rails.env}_user_id_#{order.user_id}", - currencyID: currency_id, - expireAt: order.income_payment_timeout, - amount: invoice.amount.to_i, - clientOrderID: order.public_id.to_s - } - end + delegate :income_payment_system, to: :order - def currency_id - PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: income_payment_system.currency).fiat_currency_id - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def prepare_phone_number(provider_phone_number) - "+#{provider_phone_number[0]} (#{provider_phone_number[1..3]}) #{provider_phone_number[4..6]}-#{provider_phone_number[7..8]}-#{provider_phone_number[9..10]}" - end + def invoice_fps_params + { + payerID: "#{Rails.env}_user_id_#{order.user_id}", + currencyID: currency_id, + expireAt: order.income_payment_timeout, + amount: invoice.amount.to_i, + clientOrderID: order.public_id.to_s + } + end - def valid_transaction?(transaction) - transaction && transaction['amount'].to_i == invoice.amount.to_i - end + def currency_id + PaymentServices::Paylama::CurrencyRepository.build_from(kassa_currency: income_payment_system.currency).fiat_currency_id + end + + def prepare_phone_number(provider_phone_number) + "+#{provider_phone_number[0]} (#{provider_phone_number[1..3]}) #{provider_phone_number[4..6]}-#{provider_phone_number[7..8]}-#{provider_phone_number[9..10]}" + end + + def valid_transaction?(transaction) + transaction && transaction['amount'].to_i == invoice.amount.to_i + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/perfect_money/client.rb b/lib/payment_services/perfect_money/client.rb index a2fbd0f8..920b33ad 100644 --- a/lib/payment_services/perfect_money/client.rb +++ b/lib/payment_services/perfect_money/client.rb @@ -3,123 +3,126 @@ require 'nokogiri' require 'csv' -class PaymentServices::PerfectMoney - class Client - include AutoLogger - TIMEOUT = 10 - API_URL = 'https://perfectmoney.is/acct' - - def initialize(account_id:, pass_phrase:, account:) - @account_id = account_id - @pass_phrase = pass_phrase - @account = account - end - - def create_payout(destination_account:, amount:, payment_id:) - safely_parse( - http_request( - url: "#{API_URL}/confirm.asp?", - method: :GET, - params: { - AccountID: account_id, - PassPhrase: pass_phrase, - Payer_Account: account, - Payee_Account: destination_account, - Amount: amount, - PAYMENT_ID: payment_id - } - ), - mode: :html - ) - end - def find_transaction(payment_batch_number:) - safely_parse( - http_request( - url: "#{API_URL}/historycsv.asp?", - method: :GET, - params: { - batchfilter: payment_batch_number, - AccountID: account_id, - PassPhrase: pass_phrase, - startmonth: now_utc.month, - startday: now_utc.day, - startyear: now_utc.year, - endmonth: now_utc.month, - endday: now_utc.day, - endyear: now_utc.year - } - ), - mode: :csv - ) - end +module PaymentServices + class PerfectMoney + class Client + include AutoLogger + TIMEOUT = 10 + API_URL = 'https://perfectmoney.is/acct' + + def initialize(account_id:, pass_phrase:, account:) + @account_id = account_id + @pass_phrase = pass_phrase + @account = account + end - private + def create_payout(destination_account:, amount:, payment_id:) + safely_parse( + http_request( + url: "#{API_URL}/confirm.asp?", + method: :GET, + params: { + AccountID: account_id, + PassPhrase: pass_phrase, + Payer_Account: account, + Payee_Account: destination_account, + Amount: amount, + PAYMENT_ID: payment_id + } + ), + mode: :html + ) + end - attr_reader :account_id, :pass_phrase, :account + def find_transaction(payment_batch_number:) + safely_parse( + http_request( + url: "#{API_URL}/historycsv.asp?", + method: :GET, + params: { + batchfilter: payment_batch_number, + AccountID: account_id, + PassPhrase: pass_phrase, + startmonth: now_utc.month, + startday: now_utc.day, + startyear: now_utc.year, + endmonth: now_utc.month, + endday: now_utc.day, + endyear: now_utc.year + } + ), + mode: :csv + ) + end - def http_request(url:, method:, params: nil) - uri = URI.parse(url + params.to_query) - https = http(uri) - request = build_request(uri: uri, method: method, params: params) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + private - def build_request(uri:, method:, params: nil) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = URI.encode_www_form((params.present? ? params : {})) - request - end + attr_reader :account_id, :pass_phrase, :account - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def http_request(url:, method:, params: nil) + uri = URI.parse(url + params.to_query) + https = http(uri) + request = build_request(uri: uri, method: method, params: params) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def safely_parse(response, mode:) - body = response.body - logger.info "Response: #{body}" + def build_request(uri:, method:, params: nil) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = URI.encode_www_form((params.present? ? params : {})) + request + end - if mode == :html - html_to_hash(body) - elsif mode == :csv - csv_to_hash(body) + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) end - rescue => err - logger.warn "Request failed #{response.class} #{response}" - Bugsnag.notify err do |report| - report.add_tab(:response, response_class: response.class, response_body: response) + + def safely_parse(response, mode:) + body = response.body + logger.info "Response: #{body}" + + if mode == :html + html_to_hash(body) + elsif mode == :csv + csv_to_hash(body) + end + rescue => err + logger.warn "Request failed #{response.class} #{response}" + Bugsnag.notify err do |report| + report.add_tab(:response, response_class: response.class, response_body: response) + end + response end - response - end - def html_to_hash(response) - result = {} - html = Nokogiri::HTML(response) + def html_to_hash(response) + result = {} + html = Nokogiri::HTML(response) - html.xpath('//input[@type="hidden"]').each do |input| - result[input.attributes['name'].value] = input.attributes['value'].value - end + html.xpath('//input[@type="hidden"]').each do |input| + result[input.attributes['name'].value] = input.attributes['value'].value + end - result - end + result + end - def csv_to_hash(response) - CSV.parse(response, headers: :first_row).map(&:to_h).first - end + def csv_to_hash(response) + CSV.parse(response, headers: :first_row).map(&:to_h).first + end - def now_utc - @now_utc ||= Time.now.utc + def now_utc + @now_utc ||= Time.now.utc + end end end end diff --git a/lib/payment_services/perfect_money/invoice.rb b/lib/payment_services/perfect_money/invoice.rb index fd6cb4fc..7e628ab2 100644 --- a/lib/payment_services/perfect_money/invoice.rb +++ b/lib/payment_services/perfect_money/invoice.rb @@ -2,37 +2,40 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::PerfectMoney - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'perfect_money_invoices' - scope :ordered, -> { order(id: :desc) } +module PaymentServices + class PerfectMoney + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'perfect_money_invoices' - monetize :amount_cents, as: :amount - validates :amount_cents, :order_public_id, :state, presence: true + scope :ordered, -> { order(id: :desc) } - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end + monetize :amount_cents, as: :amount + validates :amount_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled + end - state :paid do - on_entry do - order.auto_confirm!(income_amount: amount) + state :paid do + on_entry do + order.auto_confirm!(income_amount: amount) + end end + state :cancelled end - state :cancelled - end - def pay(payload:) - update(payload: payload) - end + def pay(payload:) + update(payload: payload) + end - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end end end end diff --git a/lib/payment_services/perfect_money/invoicer.rb b/lib/payment_services/perfect_money/invoicer.rb index 14e933a8..ffa37864 100644 --- a/lib/payment_services/perfect_money/invoicer.rb +++ b/lib/payment_services/perfect_money/invoicer.rb @@ -4,35 +4,38 @@ require_relative 'invoice' -class PaymentServices::PerfectMoney - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id) - end - def invoice_form_data - invoice = Invoice.find_by!(order_public_id: order.public_id) - routes_helper = Rails.application.routes.url_helpers +module PaymentServices + class PerfectMoney + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id) + end + + def invoice_form_data + invoice = Invoice.find_by!(order_public_id: order.public_id) + routes_helper = Rails.application.routes.url_helpers - { - url: 'https://perfectmoney.is/api/step1.asp', - method: 'POST', - inputs: { - PAYEE_ACCOUNT: order.income_wallet.account, - PAYEE_NAME: RestageUrlHelper::ORIGINAL_HOME_URL, - PAYMENT_ID: order.public_id, - PAYMENT_AMOUNT: format('%.2f', invoice.amount.to_f), - PAYMENT_UNITS: invoice.amount.currency.to_s, - STATUS_URL: "#{routes_helper.public_public_callbacks_api_root_url}/v1/perfect_money/receive_payment", - PAYMENT_URL: order.success_redirect, - PAYMENT_URL_METHOD: 'GET', - NOPAYMENT_URL: order.failed_redirect, - NOPAYMENT_URL_METHOD: 'GET', - SUGGESTED_MEMO: I18n.t('payment_systems.default_product', order_id: order.public_id), - BAGGAGE_FIELDS: '', - PAYMENT_METHOD: '' + { + url: 'https://perfectmoney.is/api/step1.asp', + method: 'POST', + inputs: { + PAYEE_ACCOUNT: order.income_wallet.account, + PAYEE_NAME: RestageUrlHelper::ORIGINAL_HOME_URL, + PAYMENT_ID: order.public_id, + PAYMENT_AMOUNT: format('%.2f', invoice.amount.to_f), + PAYMENT_UNITS: invoice.amount.currency.to_s, + STATUS_URL: "#{routes_helper.public_public_callbacks_api_root_url}/v1/perfect_money/receive_payment", + PAYMENT_URL: order.success_redirect, + PAYMENT_URL_METHOD: 'GET', + NOPAYMENT_URL: order.failed_redirect, + NOPAYMENT_URL_METHOD: 'GET', + SUGGESTED_MEMO: I18n.t('payment_systems.default_product', order_id: order.public_id), + BAGGAGE_FIELDS: '', + PAYMENT_METHOD: '' + } } - } + end end end end diff --git a/lib/payment_services/perfect_money/payout.rb b/lib/payment_services/perfect_money/payout.rb index baa6b90f..6e73c92c 100644 --- a/lib/payment_services/perfect_money/payout.rb +++ b/lib/payment_services/perfect_money/payout.rb @@ -1,41 +1,44 @@ # frozen_string_literal: true -class PaymentServices::PerfectMoney - class Payout < ApplicationRecord - include Workflow - self.table_name = 'perfect_money_payouts' - - scope :ordered, -> { order(id: :desc) } - - monetize :amount_cents, as: :amount - validates :amount_cents, :destination_account, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid +module PaymentServices + class PerfectMoney + class Payout < ApplicationRecord + include Workflow + + self.table_name = 'perfect_money_payouts' + + scope :ordered, -> { order(id: :desc) } + + monetize :amount_cents, as: :amount + validates :amount_cents, :destination_account, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + end + state :paid do + event :confirm, transitions_to: :completed + event :fail, transitions_to: :failed + end + state :completed + state :failed end - state :paid do - event :confirm, transitions_to: :completed - event :fail, transitions_to: :failed - end - state :completed - state :failed - end - def pay(payment_batch_number:) - update(payment_batch_number: payment_batch_number) - end + def pay(payment_batch_number:) + update(payment_batch_number: payment_batch_number) + end - def build_payment_id - "#{order_payout.order.public_id}-#{order_payout.id}" - end + def build_payment_id + "#{order_payout.order.public_id}-#{order_payout.id}" + end - private + private - def order_payout - @order_payout ||= OrderPayout.find(order_payout_id) + def order_payout + @order_payout ||= OrderPayout.find(order_payout_id) + end end end end diff --git a/lib/payment_services/perfect_money/payout_adapter.rb b/lib/payment_services/perfect_money/payout_adapter.rb index 0c05c425..9c59a0dc 100644 --- a/lib/payment_services/perfect_money/payout_adapter.rb +++ b/lib/payment_services/perfect_money/payout_adapter.rb @@ -3,41 +3,44 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::PerfectMoney - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class PerfectMoney + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - response = client.find_transaction(payment_batch_number: payout.payment_batch_number) - raise "Can't get withdrawal details" unless response + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - payout.confirm! if response['Batch'] == payout.payment_batch_number - response - end + response = client.find_transaction(payment_batch_number: payout.payment_batch_number) + raise "Can't get withdrawal details" unless response - private + payout.confirm! if response['Batch'] == payout.payment_batch_number + response + end - def make_payout(amount:, destination_account:, order_payout_id:) - payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + private - response = client.create_payout(destination_account: destination_account, amount: amount.to_d.round(2), payment_id: payout.build_payment_id) - raise "Can't process payout: #{response['ERROR']}" if response['ERROR'] + def make_payout(amount:, destination_account:, order_payout_id:) + payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - payout.pay!(payment_batch_number: response['PAYMENT_BATCH_NUM']) if response['PAYMENT_BATCH_NUM'] - end + response = client.create_payout(destination_account: destination_account, amount: amount.to_d.round(2), payment_id: payout.build_payment_id) + raise "Can't process payout: #{response['ERROR']}" if response['ERROR'] + + payout.pay!(payment_batch_number: response['PAYMENT_BATCH_NUM']) if response['PAYMENT_BATCH_NUM'] + end - def client - @client ||= begin - Client.new(account_id: wallet.merchant_id, pass_phrase: api_key, account: wallet.account) + def client + @client ||= begin + Client.new(account_id: wallet.merchant_id, pass_phrase: api_key, account: wallet.account) + end end end end diff --git a/lib/payment_services/qiwi/client.rb b/lib/payment_services/qiwi/client.rb index 012b7481..34f5d245 100644 --- a/lib/payment_services/qiwi/client.rb +++ b/lib/payment_services/qiwi/client.rb @@ -2,145 +2,148 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::QIWI - class Client - include Virtus.model strict: true - include AutoLogger - - Error = Class.new StandardError - InternalError = Class.new Error - - class ServerError < Error - # {"serviceName":"payment-history","errorCode":"auth.forbidden", - # "userMessage":"Access denied","dateTime":"2018-08-21T12:13:34.514+03:00","traceId":"dfe5e6296491abfb"} - def initialize(result) - @result = OpenStruct.new(result) - end - def message - "#{@result.errorCode}: #{@result.userMessage}" - end +module PaymentServices + class QIWI + class Client + include Virtus.model strict: true + include AutoLogger - def to_s - message - end - end + Error = Class.new StandardError + InternalError = Class.new Error - class OperationError < Error - # {"code"=>"QWPRC-1021", "message"=>"Ограничение на исходящие платежи"} - def initialize(result) - @result = OpenStruct.new(result) - end + class ServerError < Error + # {"serviceName":"payment-history","errorCode":"auth.forbidden", + # "userMessage":"Access denied","dateTime":"2018-08-21T12:13:34.514+03:00","traceId":"dfe5e6296491abfb"} + def initialize(result) + @result = OpenStruct.new(result) + end - def message - "#{@result.code}: #{@result.message}" - end + def message + "#{@result.errorCode}: #{@result.userMessage}" + end - def to_s - message + def to_s + message + end end - end - ROWS = 10 # max 50 - URL_LAST_PAYMENTS = 'https://edge.qiwi.com/payment-history/v2/persons/:phone/payments' - URL_CREATE_PAYOUT = 'https://edge.qiwi.com/sinap/api/v2/terms/99/payments' + class OperationError < Error + # {"code"=>"QWPRC-1021", "message"=>"Ограничение на исходящие платежи"} + def initialize(result) + @result = OpenStruct.new(result) + end - DEFAULT_CURRENCY = '643' + def message + "#{@result.code}: #{@result.message}" + end - attribute :phone, String - attribute :token, String + def to_s + message + end + end - def payments - list = parse_response get_payments - logger.info "Payments has #{list['data'].count} records" - list - end + ROWS = 10 # max 50 + URL_LAST_PAYMENTS = 'https://edge.qiwi.com/payment-history/v2/persons/:phone/payments' + URL_CREATE_PAYOUT = 'https://edge.qiwi.com/sinap/api/v2/terms/99/payments' - def create_payout(id:, amount:, destination_account:) - parse_response submit_payout(id: id, amount: amount, destination_account: destination_account) - end + DEFAULT_CURRENCY = '643' - private + attribute :phone, String + attribute :token, String - def timeout - @timeout ||= PaymentServices.configuration.qiwi_timeout - end + def payments + list = parse_response get_payments + logger.info "Payments has #{list['data'].count} records" + list + end - def submit_payout(id:, amount:, destination_account:) - uri = URI.parse URL_CREATE_PAYOUT - logger.info "Create payment #{uri}" - request = Net::HTTP::Post.new(uri, headers) - request.body = { - id: id.to_s, - sum: { amount: amount, currency: DEFAULT_CURRENCY }, - paymentMethod: { type: 'Account', accountId: DEFAULT_CURRENCY }, - fields: { account: destination_account } - }.to_json - logger.info "request body #{request.body}" - build_http(uri).request(request) - end + def create_payout(id:, amount:, destination_account:) + parse_response submit_payout(id: id, amount: amount, destination_account: destination_account) + end - def get_payments - uri = URI.parse(URL_LAST_PAYMENTS.gsub(':phone', phone)) - uri.query = "rows=#{ROWS}" - logger.info "Get last payments #{uri}" - response = build_http(uri).request Net::HTTP::Get.new uri, headers - logger.info "Response code: #{response.code}" + private - response - end + def timeout + @timeout ||= PaymentServices.configuration.qiwi_timeout + end - def build_http(uri) - Net::HTTP.start( - uri.host, - uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: timeout, - read_timeout: timeout - ) - end + def submit_payout(id:, amount:, destination_account:) + uri = URI.parse URL_CREATE_PAYOUT + logger.info "Create payment #{uri}" + request = Net::HTTP::Post.new(uri, headers) + request.body = { + id: id.to_s, + sum: { amount: amount, currency: DEFAULT_CURRENCY }, + paymentMethod: { type: 'Account', accountId: DEFAULT_CURRENCY }, + fields: { account: destination_account } + }.to_json + logger.info "request body #{request.body}" + build_http(uri).request(request) + end - def headers - { - 'Accept' => 'application/json', - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer #{token}" - } - end + def get_payments + uri = URI.parse(URL_LAST_PAYMENTS.gsub(':phone', phone)) + uri.query = "rows=#{ROWS}" + logger.info "Get last payments #{uri}" + response = build_http(uri).request Net::HTTP::Get.new uri, headers + logger.info "Response code: #{response.code}" - def parse_response(response) - if /json/.match?(response.content_type) - logger.debug "response is json: #{response.body}" - result = MultiJson.load response.body + response + end - if result['errorCode'].present? - logger.error "Catch server error: #{result}" - raise ServerError, result - end + def build_http(uri) + Net::HTTP.start( + uri.host, + uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: timeout, + read_timeout: timeout + ) + end - unless response.code == '200' - logger.error "Catch operation error: #{result}" - raise OperationError, result - end + def headers + { + 'Accept' => 'application/json', + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{token}" + } + end - # Пример удачного ответа - # {"id"=>"13", "terms"=>"99", "fields"=>{"account"=>"+79050274414"}, - # "sum"=>{"amount"=>30, "currency"=>"643"}, "transaction"=>{"id"=>"13774661349", - # "state"=>{"code"=>"Accepted"}}, "source"=>"account_643"} - result - elsif response.code.to_s == '500' - logger.error "#{phone}: Response code is 500, body: #{response.body}" - raise InternalError, phone - - else - logger.error "#{phone}: Unknown reponse content_type. code: #{response.code}" - logger.error "#{phone}: Unknown reponse content_type. content_type: '#{response.content_type}'" - logger.error "#{phone}: Unknown reponse content_type. body: #{response.body.to_s.force_encoding('utf-8')}" - raise InternalError, - "#{phone}: Unknown response: code=#{response.code}, \ - content_type='#{response.content_type}', \ - body: #{response.body.to_s.force_encoding('utf-8')}" + def parse_response(response) + if /json/.match?(response.content_type) + logger.debug "response is json: #{response.body}" + result = MultiJson.load response.body + + if result['errorCode'].present? + logger.error "Catch server error: #{result}" + raise ServerError, result + end + + unless response.code == '200' + logger.error "Catch operation error: #{result}" + raise OperationError, result + end + + # Пример удачного ответа + # {"id"=>"13", "terms"=>"99", "fields"=>{"account"=>"+79050274414"}, + # "sum"=>{"amount"=>30, "currency"=>"643"}, "transaction"=>{"id"=>"13774661349", + # "state"=>{"code"=>"Accepted"}}, "source"=>"account_643"} + result + elsif response.code.to_s == '500' + logger.error "#{phone}: Response code is 500, body: #{response.body}" + raise InternalError, phone + + else + logger.error "#{phone}: Unknown reponse content_type. code: #{response.code}" + logger.error "#{phone}: Unknown reponse content_type. content_type: '#{response.content_type}'" + logger.error "#{phone}: Unknown reponse content_type. body: #{response.body.to_s.force_encoding('utf-8')}" + raise InternalError, + "#{phone}: Unknown response: code=#{response.code}, \ + content_type='#{response.content_type}', \ + body: #{response.body.to_s.force_encoding('utf-8')}" + end end end end diff --git a/lib/payment_services/qiwi/importer.rb b/lib/payment_services/qiwi/importer.rb index 333028e2..738e9c89 100644 --- a/lib/payment_services/qiwi/importer.rb +++ b/lib/payment_services/qiwi/importer.rb @@ -5,91 +5,94 @@ require_relative 'payment' require_relative 'client' -class PaymentServices::QIWI - class Importer - CURRENCIES = { - 643 => :RUB - }.freeze - include Virtus.model +module PaymentServices + class QIWI + class Importer + CURRENCIES = { + 643 => :RUB + }.freeze - attribute :wallet # Wallet - attribute :logger + include Virtus.model - def import_all! - logger.info "Проверяю для кошелька #{wallet.qiwi_phone}" - payments = get_payments + attribute :wallet # Wallet + attribute :logger - if payments.blank? - logger.error "#{wallet.qiwi_phone}: в payments пусто" - return - end + def import_all! + logger.info "Проверяю для кошелька #{wallet.qiwi_phone}" + payments = get_payments + + if payments.blank? + logger.error "#{wallet.qiwi_phone}: в payments пусто" + return + end - payments.each do |data| - catch :next do - import_payment data + payments.each do |data| + catch :next do + import_payment data + end end end - end - def get_payments - build_client(wallet).payments['data'] - end + def get_payments + build_client(wallet).payments['data'] + end - def import_payment(data) - txn_id = data['txnId'] - qiwi_payment = Payment.find_by_txn_id txn_id + def import_payment(data) + txn_id = data['txnId'] + qiwi_payment = Payment.find_by_txn_id txn_id - if qiwi_payment.present? - diff = HashDiff.diff(data, qiwi_payment.data, strict: false) + if qiwi_payment.present? + diff = HashDiff.diff(data, qiwi_payment.data, strict: false) - if diff.present? - logger.info "Update #{txn_id} (#{diff}) with #{data}" + if diff.present? + logger.info "Update #{txn_id} (#{diff}) with #{data}" + else + logger.info "Skip #{txn_id}" + throw :next + end else - logger.info "Skip #{txn_id}" - throw :next + qiwi_payment = Payment.new + logger.info "Create #{txn_id} with #{data}" end - else - qiwi_payment = Payment.new - logger.info "Create #{txn_id} with #{data}" + create_from_data qiwi_payment, data + qiwi_payment.save! end - create_from_data qiwi_payment, data - qiwi_payment.save! - end - private + private - def build_client(wallet) - raise("Wallet(#{wallet.id})#qiwi_phone is empty") if wallet.qiwi_phone.blank? + def build_client(wallet) + raise("Wallet(#{wallet.id})#qiwi_phone is empty") if wallet.qiwi_phone.blank? - Client.new( - phone: Phoner::Phone.parse(wallet.qiwi_phone).to_s.tr('+', ''), # Отдаем телефон без плюса - token: wallet.api_key.presence || raise('wallet#api_key is empty') - ) - end + Client.new( + phone: Phoner::Phone.parse(wallet.qiwi_phone).to_s.tr('+', ''), # Отдаем телефон без плюса + token: wallet.api_key.presence || raise('wallet#api_key is empty') + ) + end - def parse_order_public_id(comment) - return unless comment =~ /N(\d+)/ + def parse_order_public_id(comment) + return unless comment =~ /N(\d+)/ - Regexp.last_match(1).to_i - end + Regexp.last_match(1).to_i + end - def create_from_data(qiwi_payment, data) - total = data['total'] - currency = Money::Currency.find! CURRENCIES[total['currency']] - total = Money.from_amount(total['amount'], currency) - qiwi_payment.assign_attributes( - direction_type: data['type'], - account: data['account'], - status: data['status'], - date: Time.parse(data['date']), - txn_id: data['txnId'], - comment: data['comment'], - # Пока не используем - # order_public_id: parse_order_public_id(data['comment']), - data: data, - total: total - ) + def create_from_data(qiwi_payment, data) + total = data['total'] + currency = Money::Currency.find! CURRENCIES[total['currency']] + total = Money.from_amount(total['amount'], currency) + qiwi_payment.assign_attributes( + direction_type: data['type'], + account: data['account'], + status: data['status'], + date: Time.parse(data['date']), + txn_id: data['txnId'], + comment: data['comment'], + # Пока не используем + # order_public_id: parse_order_public_id(data['comment']), + data: data, + total: total + ) + end end end end diff --git a/lib/payment_services/qiwi/invoice.rb b/lib/payment_services/qiwi/invoice.rb index dd7e6300..785a5f5a 100644 --- a/lib/payment_services/qiwi/invoice.rb +++ b/lib/payment_services/qiwi/invoice.rb @@ -2,7 +2,10 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::QIWI - class Invoice + +module PaymentServices + class QIWI + class Invoice + end end end diff --git a/lib/payment_services/qiwi/invoicer.rb b/lib/payment_services/qiwi/invoicer.rb index 6f2f98db..cc682e28 100644 --- a/lib/payment_services/qiwi/invoicer.rb +++ b/lib/payment_services/qiwi/invoicer.rb @@ -4,31 +4,34 @@ require_relative 'invoice' -class PaymentServices::QIWI - class Invoicer < ::PaymentServices::Base::Invoicer - QIWI_PAYMENT_FORM_URL = 'https://qiwi.com/payment/form' - # https://developer.qiwi.com/ru/qiwi-wallet-personal/index.html#payform - # перевод на виртуальную карту киви - QIWI_PROVIDER = 22_351 - QIWI_CURRENCY_RUB = 643 - def create_invoice(money); end +module PaymentServices + class QIWI + class Invoicer < ::PaymentServices::Base::Invoicer + QIWI_PAYMENT_FORM_URL = 'https://qiwi.com/payment/form' + # https://developer.qiwi.com/ru/qiwi-wallet-personal/index.html#payform + # перевод на виртуальную карту киви + QIWI_PROVIDER = 22_351 + QIWI_CURRENCY_RUB = 643 - def pay_invoice_url - uri = URI.parse("#{QIWI_PAYMENT_FORM_URL}/#{QIWI_PROVIDER}") - income_money = order.income_money - whole_amount, fractional_amount = income_money.fractional.abs.divmod(income_money.currency.subunit_to_unit) - uri.query = { - amountInteger: whole_amount, - amountFraction: fractional_amount, - currency: QIWI_CURRENCY_RUB, - urlSuccess: order.success_redirect, - urlFailure: order.failed_redirect, - "extra['comment']" => I18n.t('payment_systems.default_product', order_id: order.public_id), - "extra['account']" => order.income_wallet.account - }.to_query + def create_invoice(money); end - uri + def pay_invoice_url + uri = URI.parse("#{QIWI_PAYMENT_FORM_URL}/#{QIWI_PROVIDER}") + income_money = order.income_money + whole_amount, fractional_amount = income_money.fractional.abs.divmod(income_money.currency.subunit_to_unit) + uri.query = { + amountInteger: whole_amount, + amountFraction: fractional_amount, + currency: QIWI_CURRENCY_RUB, + urlSuccess: order.success_redirect, + urlFailure: order.failed_redirect, + "extra['comment']" => I18n.t('payment_systems.default_product', order_id: order.public_id), + "extra['account']" => order.income_wallet.account + }.to_query + + uri + end end end end diff --git a/lib/payment_services/qiwi/payment.rb b/lib/payment_services/qiwi/payment.rb index e7cd2bf0..008ffb6b 100644 --- a/lib/payment_services/qiwi/payment.rb +++ b/lib/payment_services/qiwi/payment.rb @@ -8,24 +8,27 @@ require_relative 'payment_order_support' -class PaymentServices::QIWI - class Payment < ApplicationRecord - include AutoLogger - extend Enumerize - include PaymentOrderSupport - self.table_name = :qiwi_payments +module PaymentServices + class QIWI + class Payment < ApplicationRecord + include AutoLogger + extend Enumerize + include PaymentOrderSupport - has_many :income_links, as: :external_payment + self.table_name = :qiwi_payments - scope :ordered, -> { order 'id desc, date desc' } - monetize :total_cents, as: :total + has_many :income_links, as: :external_payment - enum status: %i[UNKNOWN WAITING SUCCESS ERROR] - enumerize :direction_type, in: %w[IN OUT], predicates: { prefix: true } + scope :ordered, -> { order 'id desc, date desc' } + monetize :total_cents, as: :total - def success_in? - SUCCESS? && direction_type_IN? + enum status: %i[UNKNOWN WAITING SUCCESS ERROR] + enumerize :direction_type, in: %w[IN OUT], predicates: { prefix: true } + + def success_in? + SUCCESS? && direction_type_IN? + end end end end diff --git a/lib/payment_services/qiwi/payout_adapter.rb b/lib/payment_services/qiwi/payout_adapter.rb index 05f7eab2..999284be 100644 --- a/lib/payment_services/qiwi/payout_adapter.rb +++ b/lib/payment_services/qiwi/payout_adapter.rb @@ -5,32 +5,35 @@ require_relative 'client' # Сервис выплаты на QIWI. Выполняет запрос на QIWI-Клиент. # -class PaymentServices::QIWI - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - # TODO: заменить на before_ ? - # - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:) - raise 'Можно делать выплаты только в рублях' unless amount.currency == RUB - raise 'Кошелек должен быть рублевый' unless wallet.currency == RUB - - super - end - private +module PaymentServices + class QIWI + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + # TODO: заменить на before_ ? + # + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:) + raise 'Можно делать выплаты только в рублях' unless amount.currency == RUB + raise 'Кошелек должен быть рублевый' unless wallet.currency == RUB - # rubocop:disable Lint/UnusedMethodArgument - def make_payout(amount:, payment_card_details:, transaction_id:, destination_account:) - # rubocop:enable Lint/UnusedMethodArgument + super + end - client.create_payout( - id: transaction_id, - amount: amount.to_f, - destination_account: destination_account - ) - end + private + + # rubocop:disable Lint/UnusedMethodArgument + def make_payout(amount:, payment_card_details:, transaction_id:, destination_account:) + # rubocop:enable Lint/UnusedMethodArgument + + client.create_payout( + id: transaction_id, + amount: amount.to_f, + destination_account: destination_account + ) + end - def client - @client ||= Client.new phone: wallet.qiwi_phone, token: api_key + def client + @client ||= Client.new phone: wallet.qiwi_phone, token: api_key + end end end end diff --git a/lib/payment_services/rbk/client.rb b/lib/payment_services/rbk/client.rb index 7e0b39bb..20670266 100644 --- a/lib/payment_services/rbk/client.rb +++ b/lib/payment_services/rbk/client.rb @@ -2,64 +2,67 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::Rbk - class Client - include AutoLogger - TIMEOUT = 10 - API_V2 = 'https://api.rbk.money/v2' - MAX_INVOICE_LIVE = 18.minutes - SHOP = 'TEST' - DEFAULT_CURRENCY = 'RUB' - private +module PaymentServices + class Rbk + class Client + include AutoLogger + TIMEOUT = 10 + API_V2 = 'https://api.rbk.money/v2' + MAX_INVOICE_LIVE = 18.minutes + SHOP = 'TEST' + DEFAULT_CURRENCY = 'RUB' - def http_request(url:, method:, body: nil, headers: {}) - uri = URI.parse(url) - https = http(uri) - request = build_request(uri: uri, method: method, body: body, headers: headers) - logger.info "Request type: #{method} to #{uri} with payload #{request.body}" - https.request(request) - end + private - def build_request(uri:, method:, body: nil, headers: {}) - request = if method == :POST - Net::HTTP::Post.new(uri.request_uri, build_headers(headers)) - elsif method == :GET - Net::HTTP::Get.new(uri.request_uri, build_headers(headers)) - else - raise "Запрос #{method} не поддерживается!" - end - request.body = (body.present? ? body : {}).to_json - request - end + def http_request(url:, method:, body: nil, headers: {}) + uri = URI.parse(url) + https = http(uri) + request = build_request(uri: uri, method: method, body: body, headers: headers) + logger.info "Request type: #{method} to #{uri} with payload #{request.body}" + https.request(request) + end - def http(uri) - Net::HTTP.start(uri.host, uri.port, - use_ssl: true, - verify_mode: OpenSSL::SSL::VERIFY_NONE, - open_timeout: TIMEOUT, - read_timeout: TIMEOUT) - end + def build_request(uri:, method:, body: nil, headers: {}) + request = if method == :POST + Net::HTTP::Post.new(uri.request_uri, build_headers(headers)) + elsif method == :GET + Net::HTTP::Get.new(uri.request_uri, build_headers(headers)) + else + raise "Запрос #{method} не поддерживается!" + end + request.body = (body.present? ? body : {}).to_json + request + end - def build_headers(headers) - { - 'Content-Type': 'application/json; charset=utf-8', - 'Cache-Control': 'no-cache', - 'X-Request-ID': SecureRandom.hex, - 'Authorization': "Bearer #{Secrets.rbk_money_api_key}" - }.merge(headers) - end + def http(uri) + Net::HTTP.start(uri.host, uri.port, + use_ssl: true, + verify_mode: OpenSSL::SSL::VERIFY_NONE, + open_timeout: TIMEOUT, + read_timeout: TIMEOUT) + end + + def build_headers(headers) + { + 'Content-Type': 'application/json; charset=utf-8', + 'Cache-Control': 'no-cache', + 'X-Request-ID': SecureRandom.hex, + 'Authorization': "Bearer #{Secrets.rbk_money_api_key}" + }.merge(headers) + end - def safely_parse(response) - JSON.parse(response.body) - rescue JSON::ParserError => err - logger.warn "Request failed #{response.class} #{response.body}" - Bugsnag.notify err do |report| - report.add_tab(:rbk_data, - response_class: response.class, - response_body: response.body) + def safely_parse(response) + JSON.parse(response.body) + rescue JSON::ParserError => err + logger.warn "Request failed #{response.class} #{response.body}" + Bugsnag.notify err do |report| + report.add_tab(:rbk_data, + response_class: response.class, + response_body: response.body) + end + response.body end - response.body end end end diff --git a/lib/payment_services/rbk/customer.rb b/lib/payment_services/rbk/customer.rb index 237841aa..0a06aed3 100644 --- a/lib/payment_services/rbk/customer.rb +++ b/lib/payment_services/rbk/customer.rb @@ -6,85 +6,88 @@ require_relative 'payment_card' require 'jwt' -class PaymentServices::Rbk - class Customer < ApplicationRecord - self.table_name = 'rbk_money_customers' - - belongs_to :user - has_many :payment_cards, - class_name: 'PaymentServices::Rbk::PaymentCard', - foreign_key: :rbk_customer_id, - dependent: :destroy - - scope :ordered, -> { order(id: :desc) } - - validates :user_id, :rbk_id, presence: true - - # TODO: Выделить в команды - def self.create_in_rbk!(user) - response = CustomerClient.new.create_customer(user) - access_token = response['customerAccessToken']['payload'] - create!( - user_id: user.id, - rbk_id: response['customer']['id'], - access_token: access_token, - access_token_expired_at: expiration_time_from(access_token), - payload: response - ) - end - def self.expiration_time_from(token) - token_data = JWT.decode(token, nil, false).first - Time.at(token_data['exp']) - end +module PaymentServices + class Rbk + class Customer < ApplicationRecord + self.table_name = 'rbk_money_customers' - def bind_payment_card_url - refresh_token! unless access_token_valid? - - uri = URI.parse(PaymentServices::Rbk::CHECKOUT_URL) - query_hash = { - customerID: rbk_id, - customerAccessToken: access_token, - name: I18n.t('payment_systems.fill_details'), - description: I18n.t('payment_systems.bind_card_product') - } - # NOTE не используется дефолтный to_query, т.к. он кодирует пробелы в +, а нам нужно %20 - uri.query = query_hash - .collect { |key, value| "#{key}=#{ERB::Util.url_encode(value)}" } - .sort * '&' - uri - end + belongs_to :user + has_many :payment_cards, + class_name: 'PaymentServices::Rbk::PaymentCard', + foreign_key: :rbk_customer_id, + dependent: :destroy - def rbk_status - CustomerClient.new.customer_status(self) - end + scope :ordered, -> { order(id: :desc) } - def rbk_events - CustomerClient.new.customer_events(self) - end + validates :user_id, :rbk_id, presence: true - def refresh_token! - response = CustomerClient.new.get_token(self) - update!( - access_token: response['payload'], - access_token_expired_at: self.class.expiration_time_from(response['payload']) - ) - end + # TODO: Выделить в команды + def self.create_in_rbk!(user) + response = CustomerClient.new.create_customer(user) + access_token = response['customerAccessToken']['payload'] + create!( + user_id: user.id, + rbk_id: response['customer']['id'], + access_token: access_token, + access_token_expired_at: expiration_time_from(access_token), + payload: response + ) + end - def access_token_valid? - access_token_expired_at.present? && access_token_expired_at > Time.zone.now - end + def self.expiration_time_from(token) + token_data = JWT.decode(token, nil, false).first + Time.at(token_data['exp']) + end + + def bind_payment_card_url + refresh_token! unless access_token_valid? + + uri = URI.parse(PaymentServices::Rbk::CHECKOUT_URL) + query_hash = { + customerID: rbk_id, + customerAccessToken: access_token, + name: I18n.t('payment_systems.fill_details'), + description: I18n.t('payment_systems.bind_card_product') + } + # NOTE не используется дефолтный to_query, т.к. он кодирует пробелы в +, а нам нужно %20 + uri.query = query_hash + .collect { |key, value| "#{key}=#{ERB::Util.url_encode(value)}" } + .sort * '&' + uri + end + + def rbk_status + CustomerClient.new.customer_status(self) + end + + def rbk_events + CustomerClient.new.customer_events(self) + end + + def refresh_token! + response = CustomerClient.new.get_token(self) + update!( + access_token: response['payload'], + access_token_expired_at: self.class.expiration_time_from(response['payload']) + ) + end + + def access_token_valid? + access_token_expired_at.present? && access_token_expired_at > Time.zone.now + end - def create_payment_card!(card_data:) - card_details = card_data.dig(:paymentResource, :paymentToolDetails) - payment_cards.create!( - rbk_id: card_data[:id], - bin: card_details[:bin], - last_digits: card_details[:lastDigits], - brand: card_details[:paymentSystem], - card_type: (card_details[:tokenProvider] || :bank_card), - payload: card_data - ) + def create_payment_card!(card_data:) + card_details = card_data.dig(:paymentResource, :paymentToolDetails) + payment_cards.create!( + rbk_id: card_data[:id], + bin: card_details[:bin], + last_digits: card_details[:lastDigits], + brand: card_details[:paymentSystem], + card_type: (card_details[:tokenProvider] || :bank_card), + payload: card_data + ) + end end end end diff --git a/lib/payment_services/rbk/customer_client.rb b/lib/payment_services/rbk/customer_client.rb index e6fadf76..b67db5a3 100644 --- a/lib/payment_services/rbk/customer_client.rb +++ b/lib/payment_services/rbk/customer_client.rb @@ -4,52 +4,55 @@ require_relative 'client' -class PaymentServices::Rbk - class CustomerClient < PaymentServices::Rbk::Client - URL = "#{API_V2}/processing/customers" - - def create_customer(user) - request_body = { - shopID: SHOP, - contactInfo: { - email: user.email, - phone: user.phone - }, - metadata: { user_id: user.id } - } - safely_parse http_request( - url: URL, - method: :POST, - body: request_body - ) - end - - def customer_status(customer) - safely_parse http_request( - url: "#{URL}/#{customer.rbk_id}", - method: :GET - ) - end - - def customer_events(customer) - safely_parse http_request( - url: "#{URL}/#{customer.rbk_id}/events?limit=100", - method: :GET - ) - end - - def customer_bindings(customer) - safely_parse http_request( - url: "#{URL}/#{customer.rbk_id}/bindings", - method: :GET - ) - end - def get_token(customer) - safely_parse http_request( - url: "#{URL}/#{customer.rbk_id}/access-tokens", - method: :POST - ) +module PaymentServices + class Rbk + class CustomerClient < PaymentServices::Rbk::Client + URL = "#{API_V2}/processing/customers" + + def create_customer(user) + request_body = { + shopID: SHOP, + contactInfo: { + email: user.email, + phone: user.phone + }, + metadata: { user_id: user.id } + } + safely_parse http_request( + url: URL, + method: :POST, + body: request_body + ) + end + + def customer_status(customer) + safely_parse http_request( + url: "#{URL}/#{customer.rbk_id}", + method: :GET + ) + end + + def customer_events(customer) + safely_parse http_request( + url: "#{URL}/#{customer.rbk_id}/events?limit=100", + method: :GET + ) + end + + def customer_bindings(customer) + safely_parse http_request( + url: "#{URL}/#{customer.rbk_id}/bindings", + method: :GET + ) + end + + def get_token(customer) + safely_parse http_request( + url: "#{URL}/#{customer.rbk_id}/access-tokens", + method: :POST + ) + end end end end diff --git a/lib/payment_services/rbk/identity.rb b/lib/payment_services/rbk/identity.rb index 1544e36c..1be1e120 100644 --- a/lib/payment_services/rbk/identity.rb +++ b/lib/payment_services/rbk/identity.rb @@ -4,31 +4,34 @@ require_relative 'identity_client' -class PaymentServices::Rbk - class Identity < ApplicationRecord - self.table_name = 'rbk_identities' - - has_many :rbk_wallets, - class_name: 'PaymentServices::Rbk::Wallet', - foreign_key: :rbk_identity_id - has_many :rbk_payout_destinations, - class_name: 'PaymentServices::Rbk::PayoutDestination', - foreign_key: :rbk_identity_id - - def self.current - find_by(current: true) - end - def self.create_sample! - response = IdentityClient.new.create_sample_identity - create!( - rbk_id: response['id'], - payload: response - ) - end +module PaymentServices + class Rbk + class Identity < ApplicationRecord + self.table_name = 'rbk_identities' + + has_many :rbk_wallets, + class_name: 'PaymentServices::Rbk::Wallet', + foreign_key: :rbk_identity_id + has_many :rbk_payout_destinations, + class_name: 'PaymentServices::Rbk::PayoutDestination', + foreign_key: :rbk_identity_id + + def self.current + find_by(current: true) + end + + def self.create_sample! + response = IdentityClient.new.create_sample_identity + create!( + rbk_id: response['id'], + payload: response + ) + end - def current_wallet - rbk_wallets.find_by(current: true) + def current_wallet + rbk_wallets.find_by(current: true) + end end end end diff --git a/lib/payment_services/rbk/identity_client.rb b/lib/payment_services/rbk/identity_client.rb index 09d4b9be..30abc422 100644 --- a/lib/payment_services/rbk/identity_client.rb +++ b/lib/payment_services/rbk/identity_client.rb @@ -4,20 +4,23 @@ require_relative 'client' -class PaymentServices::Rbk - class IdentityClient < PaymentServices::Rbk::Client - URL = 'https://api.rbk.money/wallet/v0/identities' - def create_sample_identity - safely_parse http_request( - url: URL, - method: :POST, - body: { - name: 'Kassa.cc', - provider: 'test', - class: 'person' - } - ) +module PaymentServices + class Rbk + class IdentityClient < PaymentServices::Rbk::Client + URL = 'https://api.rbk.money/wallet/v0/identities' + + def create_sample_identity + safely_parse http_request( + url: URL, + method: :POST, + body: { + name: 'Kassa.cc', + provider: 'test', + class: 'person' + } + ) + end end end end diff --git a/lib/payment_services/rbk/invoice.rb b/lib/payment_services/rbk/invoice.rb index 49fb7fda..1d54d612 100644 --- a/lib/payment_services/rbk/invoice.rb +++ b/lib/payment_services/rbk/invoice.rb @@ -5,86 +5,89 @@ require_relative 'payment' require_relative 'invoice_client' -class PaymentServices::Rbk - class Invoice < ApplicationRecord - include Workflow - self.table_name = 'rbk_money_invoices' - - scope :ordered, -> { order(id: :desc) } - - has_many :payments, - class_name: 'PaymentServices::Rbk::Payment', - foreign_key: :rbk_money_invoice_id, - dependent: :destroy - - register_currency :rub - monetize :amount_in_cents, as: :amount, with_currency: :rub - validates :amount_in_cents, :order_public_id, :state, presence: true - - workflow_column :state - workflow do - state :pending do - event :pay, transitions_to: :paid - event :cancel, transitions_to: :cancelled - end - state :paid do - on_entry do - fetch_payments! - order.auto_confirm!(income_amount: amount) +module PaymentServices + class Rbk + class Invoice < ApplicationRecord + include Workflow + self.table_name = 'rbk_money_invoices' + + scope :ordered, -> { order(id: :desc) } + + has_many :payments, + class_name: 'PaymentServices::Rbk::Payment', + foreign_key: :rbk_money_invoice_id, + dependent: :destroy + + register_currency :rub + monetize :amount_in_cents, as: :amount, with_currency: :rub + validates :amount_in_cents, :order_public_id, :state, presence: true + + workflow_column :state + workflow do + state :pending do + event :pay, transitions_to: :paid + event :cancel, transitions_to: :cancelled end + + state :paid do + on_entry do + fetch_payments! + order.auto_confirm!(income_amount: amount) + end + end + state :cancelled + state :refunded end - state :cancelled - state :refunded - end - # FIXME: в приложение - def order - Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) - end + # FIXME: в приложение + def order + Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) + end - def make_payment(customer) - response = InvoiceClient.new.pay_invoice_by_customer(customer: customer, invoice: self) - find_or_create_payment!(response) - end + def make_payment(customer) + response = InvoiceClient.new.pay_invoice_by_customer(customer: customer, invoice: self) + find_or_create_payment!(response) + end - def refresh_info! - response = InvoiceClient.new.get_info(self) - return unless response.present? + def refresh_info! + response = InvoiceClient.new.get_info(self) + return unless response.present? - update!(payload: response) - return unless pending? + update!(payload: response) + return unless pending? - case response['status'] - when 'paid' then pay! - when 'cancelled' then cancel! + case response['status'] + when 'paid' then pay! + when 'cancelled' then cancel! + end end - end - def make_refund! - fetch_payments! if payments.empty? - payments.map(&:make_refund!).join(' ') - end + def make_refund! + fetch_payments! if payments.empty? + payments.map(&:make_refund!).join(' ') + end - def fetch_payments! - response = InvoiceClient.new.get_payments(self) - response.map { |payment_json| find_or_create_payment!(payment_json) } - end + def fetch_payments! + response = InvoiceClient.new.get_payments(self) + response.map { |payment_json| find_or_create_payment!(payment_json) } + end - private + private - def find_or_create_payment!(payment_json) - payment = payments.find_by(rbk_id: payment_json['id']) - return payment if payment.present? + def find_or_create_payment!(payment_json) + payment = payments.find_by(rbk_id: payment_json['id']) + return payment if payment.present? - Payment.create!( - rbk_id: payment_json['id'], - invoice: self, - order_public_id: order_public_id, - amount_in_cents: payment_json['amount'], - state: Payment.rbk_state_to_state(payment_json['status']), - payload: payment_json - ) + Payment.create!( + rbk_id: payment_json['id'], + invoice: self, + order_public_id: order_public_id, + amount_in_cents: payment_json['amount'], + state: Payment.rbk_state_to_state(payment_json['status']), + payload: payment_json + ) + end end end end diff --git a/lib/payment_services/rbk/invoice_client.rb b/lib/payment_services/rbk/invoice_client.rb index 88b46794..f103b6f8 100644 --- a/lib/payment_services/rbk/invoice_client.rb +++ b/lib/payment_services/rbk/invoice_client.rb @@ -4,56 +4,59 @@ require_relative 'client' -class PaymentServices::Rbk - class InvoiceClient < PaymentServices::Rbk::Client - URL = "#{API_V2}/processing/invoices" - - def create_invoice(order_id:, amount:) - request_body = { - shopID: SHOP, - dueDate: Time.zone.now + MAX_INVOICE_LIVE, - amount: amount, - currency: DEFAULT_CURRENCY, - product: I18n.t('payment_systems.default_product', order_id: order_id), - metadata: { order_public_id: order_id } - } - safely_parse http_request( - url: URL, - method: :POST, - body: request_body - ) - end - def pay_invoice_by_customer(invoice:, customer:) - request_body = { - flow: { type: 'PaymentFlowInstant' }, - payer: { - payerType: 'CustomerPayer', - customerID: customer.rbk_id +module PaymentServices + class Rbk + class InvoiceClient < PaymentServices::Rbk::Client + URL = "#{API_V2}/processing/invoices" + + def create_invoice(order_id:, amount:) + request_body = { + shopID: SHOP, + dueDate: Time.zone.now + MAX_INVOICE_LIVE, + amount: amount, + currency: DEFAULT_CURRENCY, + product: I18n.t('payment_systems.default_product', order_id: order_id), + metadata: { order_public_id: order_id } } - } - safely_parse http_request( - url: "#{URL}/#{invoice.rbk_invoice_id}/payments", - method: :POST, - body: request_body, - headers: { Authorization: "Bearer #{invoice.access_token}" } - ) - end + safely_parse http_request( + url: URL, + method: :POST, + body: request_body + ) + end - def get_info(invoice) - safely_parse http_request( - url: "#{URL}/#{invoice.rbk_invoice_id}", - method: :GET, - headers: { Authorization: "Bearer #{invoice.access_token}" } - ) - end + def pay_invoice_by_customer(invoice:, customer:) + request_body = { + flow: { type: 'PaymentFlowInstant' }, + payer: { + payerType: 'CustomerPayer', + customerID: customer.rbk_id + } + } + safely_parse http_request( + url: "#{URL}/#{invoice.rbk_invoice_id}/payments", + method: :POST, + body: request_body, + headers: { Authorization: "Bearer #{invoice.access_token}" } + ) + end + + def get_info(invoice) + safely_parse http_request( + url: "#{URL}/#{invoice.rbk_invoice_id}", + method: :GET, + headers: { Authorization: "Bearer #{invoice.access_token}" } + ) + end - def get_payments(invoice) - safely_parse http_request( - url: "#{URL}/#{invoice.rbk_invoice_id}/payments", - method: :GET, - headers: { Authorization: "Bearer #{invoice.access_token}" } - ) + def get_payments(invoice) + safely_parse http_request( + url: "#{URL}/#{invoice.rbk_invoice_id}/payments", + method: :GET, + headers: { Authorization: "Bearer #{invoice.access_token}" } + ) + end end end end diff --git a/lib/payment_services/rbk/invoicer.rb b/lib/payment_services/rbk/invoicer.rb index e7b4092d..31e6a7f4 100644 --- a/lib/payment_services/rbk/invoicer.rb +++ b/lib/payment_services/rbk/invoicer.rb @@ -6,57 +6,60 @@ require_relative 'invoice_client' require_relative 'customer' -class PaymentServices::Rbk - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - response = InvoiceClient.new.create_invoice(order_id: order.public_id, amount: money.cents) - Invoice.create!( - amount: money.to_f, - order_public_id: order.public_id, - rbk_invoice_id: response['invoice']['id'], - payload: response, - access_token: response['invoiceAccessToken']['payload'] - ) - end - def pay_invoice_url - uri = URI.parse(PaymentServices::Rbk::CHECKOUT_URL) - query_hash = { - invoiceID: invoice.rbk_invoice_id, - invoiceAccessToken: invoice.access_token, - name: I18n.t('payment_systems.default_company', order_id: order.public_id), - description: I18n.t('payment_systems.default_product', order_id: order.public_id), - bankCard: true, - applePay: false, - googlePay: false, - samsungPay: false, - amount: invoice.amount_in_cents, - locale: 'auto' - } - - # NOTE не используется дефолтный to_query, т.к. он кодирует пробелы в +, а нам нужно %20 - uri.query = query_hash - .collect { |key, value| "#{key}=#{ERB::Util.url_encode(value.to_s)}" } - .sort * '&' - - uri - end +module PaymentServices + class Rbk + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + response = InvoiceClient.new.create_invoice(order_id: order.public_id, amount: money.cents) + Invoice.create!( + amount: money.to_f, + order_public_id: order.public_id, + rbk_invoice_id: response['invoice']['id'], + payload: response, + access_token: response['invoiceAccessToken']['payload'] + ) + end - def make_refund! - invoice = PaymentServices::Rbk::Invoice.find_by!(order_public_id: order.public_id) - invoice.make_refund! - end + def pay_invoice_url + uri = URI.parse(PaymentServices::Rbk::CHECKOUT_URL) + query_hash = { + invoiceID: invoice.rbk_invoice_id, + invoiceAccessToken: invoice.access_token, + name: I18n.t('payment_systems.default_company', order_id: order.public_id), + description: I18n.t('payment_systems.default_product', order_id: order.public_id), + bankCard: true, + applePay: false, + googlePay: false, + samsungPay: false, + amount: invoice.amount_in_cents, + locale: 'auto' + } - def payments - PaymentServices::Rbk::Payment.where(order_public_id: order.public_id) - end + # NOTE не используется дефолтный to_query, т.к. он кодирует пробелы в +, а нам нужно %20 + uri.query = query_hash + .collect { |key, value| "#{key}=#{ERB::Util.url_encode(value.to_s)}" } + .sort * '&' - def invoice - @invoice ||= PaymentServices::Rbk::Invoice.find_by!(order_public_id: order.public_id) - end + uri + end + + def make_refund! + invoice = PaymentServices::Rbk::Invoice.find_by!(order_public_id: order.public_id) + invoice.make_refund! + end + + def payments + PaymentServices::Rbk::Payment.where(order_public_id: order.public_id) + end + + def invoice + @invoice ||= PaymentServices::Rbk::Invoice.find_by!(order_public_id: order.public_id) + end - def able_to_refund? - true + def able_to_refund? + true + end end end end diff --git a/lib/payment_services/rbk/payment.rb b/lib/payment_services/rbk/payment.rb index b820b2f5..31ac66ce 100644 --- a/lib/payment_services/rbk/payment.rb +++ b/lib/payment_services/rbk/payment.rb @@ -4,86 +4,89 @@ require_relative 'payment_client' -class PaymentServices::Rbk - class Payment < ApplicationRecord - include Workflow - self.table_name = 'rbk_money_payments' - - scope :ordered, -> { order(id: :desc) } - - register_currency :rub - monetize :amount_in_cents, as: :amount, with_currency: :rub - validates :amount_in_cents, :rbk_id, :state, presence: true - - belongs_to :invoice, - class_name: 'PaymentServices::Rbk::Invoice', - foreign_key: :rbk_money_invoice_id - delegate :access_token, to: :invoice - - workflow_column :state - workflow do - state :pending do - event :success, transitions_to: :succeed - event :fail, transitions_to: :failed - event :refund, transitions_to: :refunded - end - state :succeed do - on_entry do - invoice.pay! +module PaymentServices + class Rbk + class Payment < ApplicationRecord + include Workflow + self.table_name = 'rbk_money_payments' + + scope :ordered, -> { order(id: :desc) } + + register_currency :rub + monetize :amount_in_cents, as: :amount, with_currency: :rub + validates :amount_in_cents, :rbk_id, :state, presence: true + + belongs_to :invoice, + class_name: 'PaymentServices::Rbk::Invoice', + foreign_key: :rbk_money_invoice_id + delegate :access_token, to: :invoice + + workflow_column :state + workflow do + state :pending do + event :success, transitions_to: :succeed + event :fail, transitions_to: :failed + event :refund, transitions_to: :refunded end - event :refund, transitions_to: :refunded - end - state :failed do - on_entry do - invoice.cancel! + + state :succeed do + on_entry do + invoice.pay! + end + event :refund, transitions_to: :refunded end + state :failed do + on_entry do + invoice.cancel! + end + end + state :refunded end - state :refunded - end - def self.rbk_state_to_state(rbk_state) - if PaymentClient::SUCCESS_STATES.include?(rbk_state) - :success - elsif PaymentClient::FAIL_STATES.include?(rbk_state) - :fail - elsif PaymentClient::PENDING_STATES.include?(rbk_state) - :pending - elsif PaymentClient::REFUND_STATES.include?(rbk_state) - :fefunded - else - raise("Такого статуса не существует: #{rbk_state}") + def self.rbk_state_to_state(rbk_state) + if PaymentClient::SUCCESS_STATES.include?(rbk_state) + :success + elsif PaymentClient::FAIL_STATES.include?(rbk_state) + :fail + elsif PaymentClient::PENDING_STATES.include?(rbk_state) + :pending + elsif PaymentClient::REFUND_STATES.include?(rbk_state) + :fefunded + else + raise("Такого статуса не существует: #{rbk_state}") + end end - end - def make_refund! - response = PaymentClient.new.refund(self) - return unless response.present? + def make_refund! + response = PaymentClient.new.refund(self) + return unless response.present? - update!(refund_payload: response) - refund! - refund_payload - end + update!(refund_payload: response) + refund! + refund_payload + end - def refresh_info! - response = PaymentClient.new.info(self) - return unless response.present? + def refresh_info! + response = PaymentClient.new.info(self) + return unless response.present? - update!( - state: self.class.rbk_state_to_state(response['status']), - payload: response - ) - end + update!( + state: self.class.rbk_state_to_state(response['status']), + payload: response + ) + end - def fetch_refunds! - response = PaymentClient.new.refunds(self) - # FIXME: обрабатывать данные всегда как массив или всегда как хеш - response = response.first if response.is_a?(Array) - update!(refund_payload: response) - end + def fetch_refunds! + response = PaymentClient.new.refunds(self) + # FIXME: обрабатывать данные всегда как массив или всегда как хеш + response = response.first if response.is_a?(Array) + update!(refund_payload: response) + end - def payment_tool_info - payload.dig('payer', 'paymentToolDetails', 'cardNumberMask') + def payment_tool_info + payload.dig('payer', 'paymentToolDetails', 'cardNumberMask') + end end end end diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index 169ba8d5..384556f0 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -2,17 +2,20 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::Rbk - class PaymentCard < ApplicationRecord - self.table_name = 'rbk_payment_cards' - enum card_type: %i[bank_card applepay googlepay], _prefix: :card_type +module PaymentServices + class Rbk + class PaymentCard < ApplicationRecord + self.table_name = 'rbk_payment_cards' - belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id + enum card_type: %i[bank_card applepay googlepay], _prefix: :card_type - def masked_number - # NOTE dup нужен, т.к. insert изменяет исходный объект - "#{bin.dup.insert(4, ' ')}** **** #{last_digits}" + belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id + + def masked_number + # NOTE dup нужен, т.к. insert изменяет исходный объект + "#{bin.dup.insert(4, ' ')}** **** #{last_digits}" + end end end end diff --git a/lib/payment_services/rbk/payment_client.rb b/lib/payment_services/rbk/payment_client.rb index fb9b7bb5..404124f7 100644 --- a/lib/payment_services/rbk/payment_client.rb +++ b/lib/payment_services/rbk/payment_client.rb @@ -4,39 +4,42 @@ require_relative 'client' -class PaymentServices::Rbk - class PaymentClient < PaymentServices::Rbk::Client - STATES = %w[pending processed captured cancelled refunded failed].freeze - SUCCESS_STATES = %w[processed captured].freeze - FAIL_STATES = %w[cancelled failed].freeze - REFUND_STATES = %w[refunded].freeze - PENDING_STATES = %w[pending].freeze - - def refund(payment) - safely_parse http_request( - url: "#{url(payment)}/refunds", - method: :POST - ) - end - - def info(payment) - safely_parse http_request( - url: url(payment), - method: :GET - ) - end - - def refunds(payment) - safely_parse http_request( - url: "#{url(payment)}/refunds", - method: :GET - ) - end - - private - def url(payment) - "#{API_V2}/processing/invoices/#{payment.invoice.rbk_invoice_id}/payments/#{payment.rbk_id}" +module PaymentServices + class Rbk + class PaymentClient < PaymentServices::Rbk::Client + STATES = %w[pending processed captured cancelled refunded failed].freeze + SUCCESS_STATES = %w[processed captured].freeze + FAIL_STATES = %w[cancelled failed].freeze + REFUND_STATES = %w[refunded].freeze + PENDING_STATES = %w[pending].freeze + + def refund(payment) + safely_parse http_request( + url: "#{url(payment)}/refunds", + method: :POST + ) + end + + def info(payment) + safely_parse http_request( + url: url(payment), + method: :GET + ) + end + + def refunds(payment) + safely_parse http_request( + url: "#{url(payment)}/refunds", + method: :GET + ) + end + + private + + def url(payment) + "#{API_V2}/processing/invoices/#{payment.invoice.rbk_invoice_id}/payments/#{payment.rbk_id}" + end end end end diff --git a/lib/payment_services/rbk/payout.rb b/lib/payment_services/rbk/payout.rb index 611ae054..e7c922f0 100644 --- a/lib/payment_services/rbk/payout.rb +++ b/lib/payment_services/rbk/payout.rb @@ -4,45 +4,48 @@ require_relative 'payout_client' -class PaymentServices::Rbk - class Payout < ApplicationRecord - self.table_name = 'rbk_payouts' - Error = Class.new StandardError - - belongs_to :rbk_payout_destination, - class_name: 'PaymentServices::Rbk::PayoutDestination', - foreign_key: :rbk_payout_destination_id - - belongs_to :rbk_wallet, - class_name: 'PaymentServices::Rbk::Wallet', - foreign_key: :rbk_wallet_id - - def self.create_from!(destinaion:, wallet:, amount_cents:) - response = PayoutClient.new.make_payout( - payout_destination: destinaion, - wallet: wallet, - amount_cents: amount_cents - ) - raise Error, "Rbk payout error: #{response}" unless response['status'] - - create!( - rbk_id: response['id'], - rbk_payout_destination: destinaion, - rbk_wallet: wallet, - amount_cents: amount_cents, - payload: response, - rbk_status: response['status'] - ) - end - - def refresh_info! - response = PayoutClient.new.info(self) - return unless response.present? && response['status'].present? - update!( - rbk_status: response['status'], - payload: response - ) +module PaymentServices + class Rbk + class Payout < ApplicationRecord + self.table_name = 'rbk_payouts' + Error = Class.new StandardError + + belongs_to :rbk_payout_destination, + class_name: 'PaymentServices::Rbk::PayoutDestination', + foreign_key: :rbk_payout_destination_id + + belongs_to :rbk_wallet, + class_name: 'PaymentServices::Rbk::Wallet', + foreign_key: :rbk_wallet_id + + def self.create_from!(destinaion:, wallet:, amount_cents:) + response = PayoutClient.new.make_payout( + payout_destination: destinaion, + wallet: wallet, + amount_cents: amount_cents + ) + raise Error, "Rbk payout error: #{response}" unless response['status'] + + create!( + rbk_id: response['id'], + rbk_payout_destination: destinaion, + rbk_wallet: wallet, + amount_cents: amount_cents, + payload: response, + rbk_status: response['status'] + ) + end + + def refresh_info! + response = PayoutClient.new.info(self) + return unless response.present? && response['status'].present? + + update!( + rbk_status: response['status'], + payload: response + ) + end end end end diff --git a/lib/payment_services/rbk/payout_adapter.rb b/lib/payment_services/rbk/payout_adapter.rb index 77fe5076..42714281 100644 --- a/lib/payment_services/rbk/payout_adapter.rb +++ b/lib/payment_services/rbk/payout_adapter.rb @@ -5,33 +5,36 @@ require_relative 'client' # Сервис выплаты на карты с помощью РБК # -class PaymentServices::Rbk - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - # TODO: возможность передавть ID кошелька для списания - # rubocop:disable Lint/UnusedMethodArgument - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:) - # rubocop:enable Lint/UnusedMethodArgument - raise 'Можно делать выплаты только в рублях' unless amount.currency == RUB - raise 'Нет данных карты' unless payment_card_details.present? - identity = Identity.current - payout_destination = PayoutDestination.find_or_create_from_card_details( - number: payment_card_details['number'], - name: payment_card_details['name'], - exp_date: payment_card_details['exp_date'], - identity: identity - ) - payout_destination.refresh_info! - unless payout_destination.authorized? - # РБК не разрешает делать выплату по неаторизованному направлению - raise PaymentServices::UnauthorizedPayout, "РБК на разрешает вывод по направлению ##{payout_destination.id}" - end +module PaymentServices + class Rbk + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + # TODO: возможность передавть ID кошелька для списания + # rubocop:disable Lint/UnusedMethodArgument + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:) + # rubocop:enable Lint/UnusedMethodArgument + raise 'Можно делать выплаты только в рублях' unless amount.currency == RUB + raise 'Нет данных карты' unless payment_card_details.present? + + identity = Identity.current + payout_destination = PayoutDestination.find_or_create_from_card_details( + number: payment_card_details['number'], + name: payment_card_details['name'], + exp_date: payment_card_details['exp_date'], + identity: identity + ) + payout_destination.refresh_info! + unless payout_destination.authorized? + # РБК не разрешает делать выплату по неаторизованному направлению + raise PaymentServices::UnauthorizedPayout, "РБК на разрешает вывод по направлению ##{payout_destination.id}" + end - Payout.create_from!( - destinaion: payout_destination, - wallet: identity.current_wallet, - amount_cents: amount.cents - ) + Payout.create_from!( + destinaion: payout_destination, + wallet: identity.current_wallet, + amount_cents: amount.cents + ) + end end end end diff --git a/lib/payment_services/rbk/payout_client.rb b/lib/payment_services/rbk/payout_client.rb index a770971c..dcb3120d 100644 --- a/lib/payment_services/rbk/payout_client.rb +++ b/lib/payment_services/rbk/payout_client.rb @@ -4,30 +4,33 @@ require_relative 'client' -class PaymentServices::Rbk - class PayoutClient < PaymentServices::Rbk::Client - URL = 'https://api.rbk.money/wallet/v0/withdrawals' - def make_payout(payout_destination:, wallet:, amount_cents:) - safely_parse http_request( - url: URL, - method: :POST, - body: { - wallet: wallet.rbk_id, - destination: payout_destination.rbk_id, +module PaymentServices + class Rbk + class PayoutClient < PaymentServices::Rbk::Client + URL = 'https://api.rbk.money/wallet/v0/withdrawals' + + def make_payout(payout_destination:, wallet:, amount_cents:) + safely_parse http_request( + url: URL, + method: :POST, body: { - amount: amount_cents, - currency: 'RUB' # Rbk выводит только рубли + wallet: wallet.rbk_id, + destination: payout_destination.rbk_id, + body: { + amount: amount_cents, + currency: 'RUB' # Rbk выводит только рубли + } } - } - ) - end + ) + end - def info(payout) - safely_parse http_request( - url: "#{URL}/#{payout.rbk_id}", - method: :GET - ) + def info(payout) + safely_parse http_request( + url: "#{URL}/#{payout.rbk_id}", + method: :GET + ) + end end end end diff --git a/lib/payment_services/rbk/payout_destination.rb b/lib/payment_services/rbk/payout_destination.rb index a38e753e..fb1470f5 100644 --- a/lib/payment_services/rbk/payout_destination.rb +++ b/lib/payment_services/rbk/payout_destination.rb @@ -4,60 +4,63 @@ require_relative 'payout_destination_client' -class PaymentServices::Rbk - class PayoutDestination < ApplicationRecord - self.table_name = 'rbk_payout_destinations' - Error = Class.new StandardError - belongs_to :rbk_identity, class_name: 'PaymentServices::Rbk::Identity', foreign_key: :rbk_identity_id +module PaymentServices + class Rbk + class PayoutDestination < ApplicationRecord + self.table_name = 'rbk_payout_destinations' + Error = Class.new StandardError - def self.find_or_create_from_card_details(number:, name:, exp_date:, identity:) - tokenized_card = tokenize_card!(number: number, name: name, exp_date: exp_date) + belongs_to :rbk_identity, class_name: 'PaymentServices::Rbk::Identity', foreign_key: :rbk_identity_id - payout_destination = identity.rbk_payout_destinations.find_by( - payment_token: tokenized_card['token'] - ) - return payout_destination if payout_destination.present? + def self.find_or_create_from_card_details(number:, name:, exp_date:, identity:) + tokenized_card = tokenize_card!(number: number, name: name, exp_date: exp_date) - create_destination!(identity: identity, tokenized_card: tokenized_card) - end + payout_destination = identity.rbk_payout_destinations.find_by( + payment_token: tokenized_card['token'] + ) + return payout_destination if payout_destination.present? - def self.create_destination!(identity:, tokenized_card:) - public_id = SecureRandom.hex(10) - response = PayoutDestinationClient.new.create_destination( - identity: identity, - payment_token: tokenized_card['token'], - destination_public_id: public_id - ) - raise Error, "Rbk failed to create destinaion: #{response}" unless response['id'] - - create!( - rbk_identity: identity, - rbk_id: response['id'], - public_id: public_id, - card_brand: tokenized_card['paymentSystem'], - card_bin: tokenized_card['bin'], - card_suffix: tokenized_card['lastDigits'], - payment_token: tokenized_card['token'], - rbk_status: response['status'], - payload: response - ) - end + create_destination!(identity: identity, tokenized_card: tokenized_card) + end - def self.tokenize_card!(number:, name:, exp_date:) - response = PayoutDestinationClient.new.tokenize_card(number: number, name: name, exp_date: exp_date) - raise Error, "Rbk tokenization error: #{response}" unless response && response['token'].present? + def self.create_destination!(identity:, tokenized_card:) + public_id = SecureRandom.hex(10) + response = PayoutDestinationClient.new.create_destination( + identity: identity, + payment_token: tokenized_card['token'], + destination_public_id: public_id + ) + raise Error, "Rbk failed to create destinaion: #{response}" unless response['id'] - response - end + create!( + rbk_identity: identity, + rbk_id: response['id'], + public_id: public_id, + card_brand: tokenized_card['paymentSystem'], + card_bin: tokenized_card['bin'], + card_suffix: tokenized_card['lastDigits'], + payment_token: tokenized_card['token'], + rbk_status: response['status'], + payload: response + ) + end - def refresh_info! - response = PayoutDestinationClient.new.info(self) - update!(rbk_status: response['status'], payload: response) if response['status'] - end + def self.tokenize_card!(number:, name:, exp_date:) + response = PayoutDestinationClient.new.tokenize_card(number: number, name: name, exp_date: exp_date) + raise Error, "Rbk tokenization error: #{response}" unless response && response['token'].present? + + response + end + + def refresh_info! + response = PayoutDestinationClient.new.info(self) + update!(rbk_status: response['status'], payload: response) if response['status'] + end - def authorized? - rbk_status == 'Authorized' + def authorized? + rbk_status == 'Authorized' + end end end end diff --git a/lib/payment_services/rbk/payout_destination_client.rb b/lib/payment_services/rbk/payout_destination_client.rb index 4abbae3f..b6acdf22 100644 --- a/lib/payment_services/rbk/payout_destination_client.rb +++ b/lib/payment_services/rbk/payout_destination_client.rb @@ -4,45 +4,48 @@ require_relative 'client' -class PaymentServices::Rbk - class PayoutDestinationClient < PaymentServices::Rbk::Client - TOKENIZE_URL = 'https://api.rbk.money/payres/v0/bank-cards' - URL = 'https://api.rbk.money/wallet/v0/destinations' - def tokenize_card(number:, exp_date:, name:) - safely_parse http_request( - url: TOKENIZE_URL, - method: :POST, - body: { - type: 'BankCard', - cardNumber: number, - expDate: exp_date, - cardHolder: name.upcase - } - ) - end +module PaymentServices + class Rbk + class PayoutDestinationClient < PaymentServices::Rbk::Client + TOKENIZE_URL = 'https://api.rbk.money/payres/v0/bank-cards' + URL = 'https://api.rbk.money/wallet/v0/destinations' - def create_destination(identity:, payment_token:, destination_public_id:) - safely_parse http_request( - url: URL, - method: :POST, - body: { - name: "Destination #{destination_public_id}", - identity: identity.rbk_id, - currency: 'RUB', - resource: { - type: 'BankCardDestinationResource', - token: payment_token + def tokenize_card(number:, exp_date:, name:) + safely_parse http_request( + url: TOKENIZE_URL, + method: :POST, + body: { + type: 'BankCard', + cardNumber: number, + expDate: exp_date, + cardHolder: name.upcase } - } - ) - end + ) + end + + def create_destination(identity:, payment_token:, destination_public_id:) + safely_parse http_request( + url: URL, + method: :POST, + body: { + name: "Destination #{destination_public_id}", + identity: identity.rbk_id, + currency: 'RUB', + resource: { + type: 'BankCardDestinationResource', + token: payment_token + } + } + ) + end - def info(payout_destination) - safely_parse http_request( - url: "#{URL}/#{payout_destination.rbk_id}", - method: :GET - ) + def info(payout_destination) + safely_parse http_request( + url: "#{URL}/#{payout_destination.rbk_id}", + method: :GET + ) + end end end end diff --git a/lib/payment_services/rbk/wallet.rb b/lib/payment_services/rbk/wallet.rb index c297ea2c..c7d53dcc 100644 --- a/lib/payment_services/rbk/wallet.rb +++ b/lib/payment_services/rbk/wallet.rb @@ -4,18 +4,21 @@ require_relative 'wallet_client' -class PaymentServices::Rbk - class Wallet < ApplicationRecord - self.table_name = 'rbk_wallets' - belongs_to :rbk_identity, class_name: 'PaymentServices::Rbk::Identity', foreign_key: :rbk_identity_id +module PaymentServices + class Rbk + class Wallet < ApplicationRecord + self.table_name = 'rbk_wallets' - def self.create_for_identity(identity) - response = WalletClient.new.create_wallet(identity: identity) - identity.rbk_wallets.create!( - rbk_id: response['id'], - payload: response - ) + belongs_to :rbk_identity, class_name: 'PaymentServices::Rbk::Identity', foreign_key: :rbk_identity_id + + def self.create_for_identity(identity) + response = WalletClient.new.create_wallet(identity: identity) + identity.rbk_wallets.create!( + rbk_id: response['id'], + payload: response + ) + end end end end diff --git a/lib/payment_services/rbk/wallet_client.rb b/lib/payment_services/rbk/wallet_client.rb index c57ec2df..219fbd2c 100644 --- a/lib/payment_services/rbk/wallet_client.rb +++ b/lib/payment_services/rbk/wallet_client.rb @@ -4,20 +4,23 @@ require_relative 'client' -class PaymentServices::Rbk - class WalletClient < PaymentServices::Rbk::Client - URL = 'https://api.rbk.money/wallet/v0/wallets' - def create_wallet(identity:) - safely_parse http_request( - url: URL, - method: :POST, - body: { - name: 'Kassa.cc payouts wallet', - identity: identity.rbk_id, - currency: 'RUB' - } - ) +module PaymentServices + class Rbk + class WalletClient < PaymentServices::Rbk::Client + URL = 'https://api.rbk.money/wallet/v0/wallets' + + def create_wallet(identity:) + safely_parse http_request( + url: URL, + method: :POST, + body: { + name: 'Kassa.cc payouts wallet', + identity: identity.rbk_id, + currency: 'RUB' + } + ) + end end end end diff --git a/lib/payment_services/transfera/client.rb b/lib/payment_services/transfera/client.rb index 2320aa24..4291b8bb 100644 --- a/lib/payment_services/transfera/client.rb +++ b/lib/payment_services/transfera/client.rb @@ -1,43 +1,46 @@ # frozen_string_literal: true -class PaymentServices::Transfera - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.transfera.io' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end - - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/integrations/ru/transactions/new/", - method: :POST, - body: params.merge(merchantToken: api_key, hmacHash: signature(params)).to_json, - headers: build_headers - ) - end - - def transaction(transaction_id:) - safely_parse http_request( - url: "#{API_URL}/integrations/ru/transactions/#{transaction_id}", - method: :GET, - headers: build_headers - ) - end - - private - - attr_reader :api_key, :secret_key - - def build_headers - { - 'Content-Type' => 'application/json' - } - end - - def signature(params) - OpenSSL::HMAC.hexdigest('SHA512', secret_key, [params[:amount], params[:currency], api_key].join('::')) +module PaymentServices + class Transfera + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.transfera.io' + + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end + + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/integrations/ru/transactions/new/", + method: :POST, + body: params.merge(merchantToken: api_key, hmacHash: signature(params)).to_json, + headers: build_headers + ) + end + + def transaction(transaction_id:) + safely_parse http_request( + url: "#{API_URL}/integrations/ru/transactions/#{transaction_id}", + method: :GET, + headers: build_headers + ) + end + + private + + attr_reader :api_key, :secret_key + + def build_headers + { + 'Content-Type' => 'application/json' + } + end + + def signature(params) + OpenSSL::HMAC.hexdigest('SHA512', secret_key, [params[:amount], params[:currency], api_key].join('::')) + end end end end diff --git a/lib/payment_services/transfera/invoice.rb b/lib/payment_services/transfera/invoice.rb index b80bea99..51c0e1a7 100644 --- a/lib/payment_services/transfera/invoice.rb +++ b/lib/payment_services/transfera/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Transfera - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'Success' - FAILED_PROVIDER_STATE = 'Fail' - self.table_name = 'transferas_invoices' +module PaymentServices + class Transfera + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'Success' + FAILED_PROVIDER_STATE = 'Fail' - monetize :amount_cents, as: :amount + self.table_name = 'transferas_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/transfera/invoicer.rb b/lib/payment_services/transfera/invoicer.rb index 409b6c22..28578a90 100644 --- a/lib/payment_services/transfera/invoicer.rb +++ b/lib/payment_services/transfera/invoicer.rb @@ -3,66 +3,69 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Transfera - class Invoicer < ::PaymentServices::Base::Invoicer - SBP_PAYMENT_METHOD = 'SBP' - Error = Class.new StandardError - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_params) - raise Error, "Can't create invoice" unless response.dig('data', 'order_id') +module PaymentServices + class Transfera + class Invoicer < ::PaymentServices::Base::Invoicer + SBP_PAYMENT_METHOD = 'SBP' + Error = Class.new StandardError - invoice.update!(deposit_id: response.dig('data', 'order_id')) - PaymentServices::Base::Wallet.new( - address: response.dig('data', 'card'), - name: nil - ) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_params) + raise Error, "Can't create invoice" unless response.dig('data', 'order_id') - def create_invoice(money) - invoice - end + invoice.update!(deposit_id: response.dig('data', 'order_id')) + PaymentServices::Base::Wallet.new( + address: response.dig('data', 'card'), + name: nil + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.transaction(transaction_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction.dig('data', 'status')) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(transaction_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction.dig('data', 'status')) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :card_bank, :sbp?, to: :bank_resolver + private - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + delegate :card_bank, :sbp?, to: :bank_resolver - def invoice_params - { - amount: invoice.amount.to_f, - currency: invoice.amount_currency.to_s, - payload: { - id: order.public_id.to_s - }, - cardType: sbp? ? SBP_PAYMENT_METHOD : card_bank, - transaction_type: 'PAY_IN' - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def invoice_params + { + amount: invoice.amount.to_f, + currency: invoice.amount_currency.to_s, + payload: { + id: order.public_id.to_s + }, + cardType: sbp? ? SBP_PAYMENT_METHOD : card_bank, + transaction_type: 'PAY_IN' + } + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/tronscan/client.rb b/lib/payment_services/tronscan/client.rb index 72fea35d..f80fdf4d 100644 --- a/lib/payment_services/tronscan/client.rb +++ b/lib/payment_services/tronscan/client.rb @@ -1,47 +1,50 @@ # frozen_string_literal: true -class PaymentServices::Tronscan - class Client < ::PaymentServices::Base::Client - API_URL = 'https://apilist.tronscanapi.com/api' - USDT_TRC_CONTRACT_ADDRESS = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' - CURRENCY_TO_ENDPOINT = { - 'trx' => 'transaction', - 'usdt' => 'new/token_trc20/transfers' - }.freeze - - def initialize(api_key:, currency:) - @api_key = api_key - @currency = currency.inquiry - end - def transactions(address:) - if currency.usdt? - params = { toAddress: address, contract_address: USDT_TRC_CONTRACT_ADDRESS } - else - params = { address: address, limit: 100 } +module PaymentServices + class Tronscan + class Client < ::PaymentServices::Base::Client + API_URL = 'https://apilist.tronscanapi.com/api' + USDT_TRC_CONTRACT_ADDRESS = 'TR7NHqjeKQxGTCi8q8ZY4pL8otSzgjLj6t' + CURRENCY_TO_ENDPOINT = { + 'trx' => 'transaction', + 'usdt' => 'new/token_trc20/transfers' + }.freeze + + def initialize(api_key:, currency:) + @api_key = api_key + @currency = currency.inquiry end - params = params.to_query - response = safely_parse(http_request( - url: "#{API_URL}/#{endpoint}?#{params}", - method: :GET, - headers: build_headers - )) - response['data'] || response['token_transfers'] - end + def transactions(address:) + if currency.usdt? + params = { toAddress: address, contract_address: USDT_TRC_CONTRACT_ADDRESS } + else + params = { address: address, limit: 100 } + end + + params = params.to_query + response = safely_parse(http_request( + url: "#{API_URL}/#{endpoint}?#{params}", + method: :GET, + headers: build_headers + )) + response['data'] || response['token_transfers'] + end - private + private - attr_reader :api_key, :currency + attr_reader :api_key, :currency - def build_headers - { - 'TRON-PRO-API-KEY' => api_key - } - end + def build_headers + { + 'TRON-PRO-API-KEY' => api_key + } + end - def endpoint - CURRENCY_TO_ENDPOINT[currency] || raise("#{currency} is not supported") + def endpoint + CURRENCY_TO_ENDPOINT[currency] || raise("#{currency} is not supported") + end end end end diff --git a/lib/payment_services/tronscan/invoice.rb b/lib/payment_services/tronscan/invoice.rb index be14bfeb..6aa4f3f9 100644 --- a/lib/payment_services/tronscan/invoice.rb +++ b/lib/payment_services/tronscan/invoice.rb @@ -1,16 +1,19 @@ # frozen_string_literal: true -class PaymentServices::Tronscan - class Invoice < ::PaymentServices::Base::CryptoInvoice - self.table_name = 'tronscan_invoices' - monetize :amount_cents, as: :amount +module PaymentServices + class Tronscan + class Invoice < ::PaymentServices::Base::CryptoInvoice + self.table_name = 'tronscan_invoices' - def update_invoice_details(transaction:) - bind_transaction! if pending? - update!(transaction_created_at: transaction.created_at, transaction_id: transaction.id) + monetize :amount_cents, as: :amount - pay!(payload: transaction) if transaction.successful? + def update_invoice_details(transaction:) + bind_transaction! if pending? + update!(transaction_created_at: transaction.created_at, transaction_id: transaction.id) + + pay!(payload: transaction) if transaction.successful? + end end end end diff --git a/lib/payment_services/tronscan/invoicer.rb b/lib/payment_services/tronscan/invoicer.rb index bd962cf4..b6de5a5e 100644 --- a/lib/payment_services/tronscan/invoicer.rb +++ b/lib/payment_services/tronscan/invoicer.rb @@ -4,42 +4,45 @@ require_relative 'client' require_relative 'transaction_matcher' -class PaymentServices::Tronscan - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money) - Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) - end - def async_invoice_state_updater? - true - end +module PaymentServices + class Tronscan + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money) + Invoice.create!(amount: money, order_public_id: order.public_id, address: order.income_account_emoney) + end - def update_invoice_state! - transaction = transaction_for(invoice) - return if transaction.nil? + def async_invoice_state_updater? + true + end - invoice.update_invoice_details(transaction: transaction) - end + def update_invoice_state! + transaction = transaction_for(invoice) + return if transaction.nil? - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + invoice.update_invoice_details(transaction: transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :income_payment_system, to: :order - delegate :currency, to: :income_payment_system + private - def transaction_for(invoice) - TransactionMatcher.new(invoice: invoice, transactions: collect_transactions).perform - end + delegate :income_payment_system, to: :order + delegate :currency, to: :income_payment_system - def collect_transactions - client.transactions(address: invoice.address) - end + def transaction_for(invoice) + TransactionMatcher.new(invoice: invoice, transactions: collect_transactions).perform + end + + def collect_transactions + client.transactions(address: invoice.address) + end - def client - @client ||= Client.new(api_key: api_key, currency: currency.to_s.downcase) + def client + @client ||= Client.new(api_key: api_key, currency: currency.to_s.downcase) + end end end end diff --git a/lib/payment_services/tronscan/transaction.rb b/lib/payment_services/tronscan/transaction.rb index f6599794..a1c008ec 100644 --- a/lib/payment_services/tronscan/transaction.rb +++ b/lib/payment_services/tronscan/transaction.rb @@ -1,27 +1,30 @@ # frozen_string_literal: true -class PaymentServices::Tronscan - class Transaction - include Virtus.model - attribute :id, String - attribute :created_at, DateTime - attribute :source, Hash +module PaymentServices + class Tronscan + class Transaction + include Virtus.model - def self.build_from(raw_transaction:) - new( - id: raw_transaction[:id], - created_at: raw_transaction[:created_at], - source: raw_transaction[:source].deep_symbolize_keys - ) - end + attribute :id, String + attribute :created_at, DateTime + attribute :source, Hash - def to_s - source.to_s - end + def self.build_from(raw_transaction:) + new( + id: raw_transaction[:id], + created_at: raw_transaction[:created_at], + source: raw_transaction[:source].deep_symbolize_keys + ) + end + + def to_s + source.to_s + end - def successful? - source[:confirmed] + def successful? + source[:confirmed] + end end end end diff --git a/lib/payment_services/tronscan/transaction_matcher.rb b/lib/payment_services/tronscan/transaction_matcher.rb index 9eb6f484..ffd8ba42 100644 --- a/lib/payment_services/tronscan/transaction_matcher.rb +++ b/lib/payment_services/tronscan/transaction_matcher.rb @@ -2,67 +2,70 @@ require_relative 'transaction' -class PaymentServices::Tronscan - class TransactionMatcher - def initialize(invoice:, transactions:) - @invoice = invoice - @transactions = transactions - @currency = invoice.amount_currency.to_s.downcase - end - def perform - send("match_#{currency}_transaction") - end +module PaymentServices + class Tronscan + class TransactionMatcher + def initialize(invoice:, transactions:) + @invoice = invoice + @transactions = transactions + @currency = invoice.amount_currency.to_s.downcase + end - private + def perform + send("match_#{currency}_transaction") + end - attr_reader :invoice, :transactions, :currency + private - def build_transaction(id:, created_at:, source:) - Transaction.build_from(raw_transaction: { id: id, created_at: created_at, source: source }) - end + attr_reader :invoice, :transactions, :currency - def match_trx_transaction - raw_transaction = transactions.find { |transaction| match_trx_transaction?(transaction) } - return unless raw_transaction + def build_transaction(id:, created_at:, source:) + Transaction.build_from(raw_transaction: { id: id, created_at: created_at, source: source }) + end - build_transaction( - id: raw_transaction['hash'], - created_at: timestamp_in_utc(raw_transaction['timestamp'] / 1000), - source: raw_transaction - ) - end + def match_trx_transaction + raw_transaction = transactions.find { |transaction| match_trx_transaction?(transaction) } + return unless raw_transaction - def match_trx_transaction?(transaction) - match_amount?(transaction['amount'], transaction['tokenInfo']['tokenDecimal']) && match_time?(transaction['timestamp'] / 1000) - end + build_transaction( + id: raw_transaction['hash'], + created_at: timestamp_in_utc(raw_transaction['timestamp'] / 1000), + source: raw_transaction + ) + end - def match_usdt_transaction - raw_transaction = transactions.find { |transaction| match_usdt_transaction?(transaction) } - return unless raw_transaction + def match_trx_transaction?(transaction) + match_amount?(transaction['amount'], transaction['tokenInfo']['tokenDecimal']) && match_time?(transaction['timestamp'] / 1000) + end - build_transaction( - id: raw_transaction['transaction_id'], - created_at: timestamp_in_utc(raw_transaction['block_ts'] / 1000), - source: raw_transaction - ) - end + def match_usdt_transaction + raw_transaction = transactions.find { |transaction| match_usdt_transaction?(transaction) } + return unless raw_transaction - def match_usdt_transaction?(transaction) - match_amount?(transaction['quant'], transaction['tokenInfo']['tokenDecimal']) && match_time?(transaction['block_ts'] / 1000) - end + build_transaction( + id: raw_transaction['transaction_id'], + created_at: timestamp_in_utc(raw_transaction['block_ts'] / 1000), + source: raw_transaction + ) + end - def match_amount?(received_amount, decimals) - amount = received_amount.to_i / 10.0 ** decimals - amount == invoice.amount.to_f - end + def match_usdt_transaction?(transaction) + match_amount?(transaction['quant'], transaction['tokenInfo']['tokenDecimal']) && match_time?(transaction['block_ts'] / 1000) + end - def match_time?(timestamp) - invoice.created_at.utc < timestamp_in_utc(timestamp) - end + def match_amount?(received_amount, decimals) + amount = received_amount.to_i / 10.0 ** decimals + amount == invoice.amount.to_f + end + + def match_time?(timestamp) + invoice.created_at.utc < timestamp_in_utc(timestamp) + end - def timestamp_in_utc(timestamp) - Time.at(timestamp).to_datetime.utc + def timestamp_in_utc(timestamp) + Time.at(timestamp).to_datetime.utc + end end end end diff --git a/lib/payment_services/wallex/client.rb b/lib/payment_services/wallex/client.rb index a9bed00a..c86b92e4 100644 --- a/lib/payment_services/wallex/client.rb +++ b/lib/payment_services/wallex/client.rb @@ -1,72 +1,75 @@ # frozen_string_literal: true -class PaymentServices::Wallex - class Client < ::PaymentServices::Base::Client - API_URL = 'https://wallex.online' - MERCHANT_ID = 286 - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class Wallex + class Client < ::PaymentServices::Base::Client + API_URL = 'https://wallex.online' + MERCHANT_ID = 286 - def create_invoice(params:) - sign = signature(sign_str: sign_string(params: params, param_names: [:client, :uuid, :amount, :fiat_currency, :payment_method])) - safely_parse http_request( - url: "#{API_URL}/exchange/create_deal_v2/#{MERCHANT_ID}", - method: :POST, - body: params.merge(sign: sign).to_json, - headers: build_headers - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def invoice_transaction(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/exchange/get?id=#{deposit_id}", - method: :GET, - headers: build_headers - ) - end + def create_invoice(params:) + sign = signature(sign_str: sign_string(params: params, param_names: [:client, :uuid, :amount, :fiat_currency, :payment_method])) + safely_parse http_request( + url: "#{API_URL}/exchange/create_deal_v2/#{MERCHANT_ID}", + method: :POST, + body: params.merge(sign: sign).to_json, + headers: build_headers + ) + end - def create_payout(params:) - params[:merchant] = MERCHANT_ID - sign = signature(sign_str: sign_string(params: params, param_names: [:merchant, :amount, :currency, :number, :bank, :type, :fiat])) - safely_parse http_request( - url: "#{API_URL}/payout/new", - method: :POST, - body: params.merge(sign: sign).to_json, - headers: build_headers - ) - end + def invoice_transaction(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/exchange/get?id=#{deposit_id}", + method: :GET, + headers: build_headers + ) + end - def payout_transaction(payout_id:) - params = { merchant: MERCHANT_ID, id: payout_id } - sign = signature(sign_str: sign_string(params: params, param_names: [:merchant, :id])) - safely_parse http_request( - url: "#{API_URL}/payout/get", - method: :POST, - body: params.merge(sign: sign).to_json, - headers: build_headers - ) - end + def create_payout(params:) + params[:merchant] = MERCHANT_ID + sign = signature(sign_str: sign_string(params: params, param_names: [:merchant, :amount, :currency, :number, :bank, :type, :fiat])) + safely_parse http_request( + url: "#{API_URL}/payout/new", + method: :POST, + body: params.merge(sign: sign).to_json, + headers: build_headers + ) + end - private + def payout_transaction(payout_id:) + params = { merchant: MERCHANT_ID, id: payout_id } + sign = signature(sign_str: sign_string(params: params, param_names: [:merchant, :id])) + safely_parse http_request( + url: "#{API_URL}/payout/get", + method: :POST, + body: params.merge(sign: sign).to_json, + headers: build_headers + ) + end - attr_reader :api_key, :secret_key + private - def build_headers - { - 'Content-Type' => 'application/json', - 'X-Api-Key' => api_key - } - end + attr_reader :api_key, :secret_key - def sign_string(params:, param_names:) - params.slice(*param_names).values.join + secret_key - end + def build_headers + { + 'Content-Type' => 'application/json', + 'X-Api-Key' => api_key + } + end + + def sign_string(params:, param_names:) + params.slice(*param_names).values.join + secret_key + end - def signature(sign_str:) - Digest::SHA1.hexdigest(sign_str) + def signature(sign_str:) + Digest::SHA1.hexdigest(sign_str) + end end end end diff --git a/lib/payment_services/wallex/invoice.rb b/lib/payment_services/wallex/invoice.rb index ccd42613..34623063 100644 --- a/lib/payment_services/wallex/invoice.rb +++ b/lib/payment_services/wallex/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Wallex - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 4 - FAILED_PROVIDER_STATE = 2 - self.table_name = 'wallex_invoices' +module PaymentServices + class Wallex + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 4 + FAILED_PROVIDER_STATE = 2 - monetize :amount_cents, as: :amount + self.table_name = 'wallex_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/wallex/invoicer.rb b/lib/payment_services/wallex/invoicer.rb index 9e84a7bb..e67d6045 100644 --- a/lib/payment_services/wallex/invoicer.rb +++ b/lib/payment_services/wallex/invoicer.rb @@ -3,68 +3,71 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::Wallex - class Invoicer < ::PaymentServices::Base::Invoicer - SBP_PAYMENT_METHOD = 'sbp' - CARD_PAYMENT_METHOD = 'c2c' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_p2p_params) - raise response['message'] unless response['success'] +module PaymentServices + class Wallex + class Invoicer < ::PaymentServices::Base::Invoicer + SBP_PAYMENT_METHOD = 'sbp' + CARD_PAYMENT_METHOD = 'c2c' - invoice.update!(deposit_id: response['id']) - PaymentServices::Base::Wallet.new( - address: response.dig('paymentInfo', 'paymentCredentials'), - name: nil, - memo: response.dig('paymentInfo', 'paymentComment') - ) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_p2p_params) + raise response['message'] unless response['success'] - def create_invoice(money) - invoice - end + invoice.update!(deposit_id: response['id']) + PaymentServices::Base::Wallet.new( + address: response.dig('paymentInfo', 'paymentCredentials'), + name: nil, + memo: response.dig('paymentInfo', 'paymentComment') + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.invoice_transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['status']) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.invoice_transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['status']) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver + private - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver - def invoice_p2p_params - params = { - client: order.user.email, - amount: invoice.amount.to_f.to_s, - fiat_currency: invoice.amount_currency.to_s.downcase, - uuid: order.public_id.to_s, - payment_method: sbp? ? SBP_PAYMENT_METHOD : CARD_PAYMENT_METHOD - } - params[:bank] = sbp_bank if sbp? && sbp_bank.present? - params[:bank] = card_bank unless sbp? - params - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def invoice_p2p_params + params = { + client: order.user.email, + amount: invoice.amount.to_f.to_s, + fiat_currency: invoice.amount_currency.to_s.downcase, + uuid: order.public_id.to_s, + payment_method: sbp? ? SBP_PAYMENT_METHOD : CARD_PAYMENT_METHOD + } + params[:bank] = sbp_bank if sbp? && sbp_bank.present? + params[:bank] = card_bank unless sbp? + params + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/wallex/payout.rb b/lib/payment_services/wallex/payout.rb index 0a4c5da8..ec95ee24 100644 --- a/lib/payment_services/wallex/payout.rb +++ b/lib/payment_services/wallex/payout.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::Wallex - class Payout < ::PaymentServices::Base::FiatPayout - SUCCESS_PROVIDER_STATE = 3 - FAILED_PROVIDER_STATE = 2 - self.table_name = 'wallex_payouts' +module PaymentServices + class Wallex + class Payout < ::PaymentServices::Base::FiatPayout + SUCCESS_PROVIDER_STATE = 3 + FAILED_PROVIDER_STATE = 2 - monetize :amount_cents, as: :amount + self.table_name = 'wallex_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state == FAILED_PROVIDER_STATE + def provider_failed? + provider_state == FAILED_PROVIDER_STATE + end end end end diff --git a/lib/payment_services/wallex/payout_adapter.rb b/lib/payment_services/wallex/payout_adapter.rb index f6528252..da739147 100644 --- a/lib/payment_services/wallex/payout_adapter.rb +++ b/lib/payment_services/wallex/payout_adapter.rb @@ -3,62 +3,65 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::Wallex - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - PAYOUT_SUCCESS_STATE = 'success' - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end +module PaymentServices + class Wallex + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + PAYOUT_SUCCESS_STATE = 'success' - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - transaction = client.payout_transaction(payout_id: payout.withdrawal_id) - payout.update_state_by_provider(transaction.dig('item', 'status')) if transaction - transaction - end + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - private + transaction = client.payout_transaction(payout_id: payout.withdrawal_id) + payout.update_state_by_provider(transaction.dig('item', 'status')) if transaction + transaction + end - delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver + private - attr_reader :payout + delegate :card_bank, :sbp_bank, :sbp?, to: :bank_resolver - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_payout(params: payout_params) - raise response['error'] unless response['status'] == PAYOUT_SUCCESS_STATE + attr_reader :payout - payout.pay!(withdrawal_id: response['id']) - end + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_payout(params: payout_params) + raise response['error'] unless response['status'] == PAYOUT_SUCCESS_STATE - def payout_params - order = OrderPayout.find(payout.order_payout_id).order - params = { - uuid: "#{Rails.env}_#{payout.id}", - amount: payout.amount.to_f.to_s, - currency: 'rub', - type: 'fiat', - bank: card_bank, - fiat: 'rub' - } - params[:number] = sbp? ? order.outcome_phone : order.destination_account - params[:bankCode] = sbp_bank if sbp? - params - end + payout.pay!(withdrawal_id: response['id']) + end - def bank_resolver - @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def payout_params + order = OrderPayout.find(payout.order_payout_id).order + params = { + uuid: "#{Rails.env}_#{payout.id}", + amount: payout.amount.to_f.to_s, + currency: 'rub', + type: 'fiat', + bank: card_bank, + fiat: 'rub' + } + params[:number] = sbp? ? order.outcome_phone : order.destination_account + params[:bankCode] = sbp_bank if sbp? + params + end + + def bank_resolver + @bank_resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/x_pay_pro/client.rb b/lib/payment_services/x_pay_pro/client.rb index e09e034d..ad81d5c3 100644 --- a/lib/payment_services/x_pay_pro/client.rb +++ b/lib/payment_services/x_pay_pro/client.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::XPayPro - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.xpaypro.dev/v1/merchant-api' - def initialize(api_key:) - @api_key = api_key - end +module PaymentServices + class XPayPro + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.xpaypro.dev/v1/merchant-api' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/txs/p2p/invoice", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end + def initialize(api_key:) + @api_key = api_key + end - def transaction(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/txs/#{deposit_id}", - method: :GET, - headers: build_headers - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/txs/p2p/invoice", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end + + def transaction(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/txs/#{deposit_id}", + method: :GET, + headers: build_headers + ) + end - private + private - attr_reader :api_key + attr_reader :api_key - def build_headers - { - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer #{api_key}" - } + def build_headers + { + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{api_key}" + } + end end end end diff --git a/lib/payment_services/x_pay_pro/invoice.rb b/lib/payment_services/x_pay_pro/invoice.rb index 1c73324f..a3a2d712 100644 --- a/lib/payment_services/x_pay_pro/invoice.rb +++ b/lib/payment_services/x_pay_pro/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::XPayPro - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'TX_SUCCESS' - FAILED_PROVIDER_STATES = %w(TX_CANCELLED TX_EXPIRED) - self.table_name = 'xpaypro_invoices' +module PaymentServices + class XPayPro + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'TX_SUCCESS' + FAILED_PROVIDER_STATES = %w(TX_CANCELLED TX_EXPIRED) - monetize :amount_cents, as: :amount + self.table_name = 'xpaypro_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/x_pay_pro/invoicer.rb b/lib/payment_services/x_pay_pro/invoicer.rb index 6b8f1aa7..d171d3ee 100644 --- a/lib/payment_services/x_pay_pro/invoicer.rb +++ b/lib/payment_services/x_pay_pro/invoicer.rb @@ -3,70 +3,73 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::XPayPro - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_p2p_params) - raise response['message'] if response['code'] - invoice.update!( - deposit_id: response.dig('tx', 'tx_id'), - rate: response.dig('tx', 'rate').to_f - ) - PaymentServices::Base::Wallet.new( - address: response.dig('tx', 'payment_requisite'), - name: nil, - memo: response.dig('tx', 'payment_system').downcase.capitalize - ) - end +module PaymentServices + class XPayPro + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_p2p_params) + raise response['message'] if response['code'] - def create_invoice(money) - invoice - end + invoice.update!( + deposit_id: response.dig('tx', 'tx_id'), + rate: response.dig('tx', 'rate').to_f + ) + PaymentServices::Base::Wallet.new( + address: response.dig('tx', 'payment_requisite'), + name: nil, + memo: response.dig('tx', 'payment_system').downcase.capitalize + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction.dig('tx', 'tx_status')) if transaction_valid?(transaction) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction.dig('tx', 'tx_status')) if transaction_valid?(transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_p2p_params - { - fiat_currency: 'RUB', - fiat_amount: invoice.amount.to_f.to_s, - crypto_currency: 'USDT', - payment_method: 'BANK_CARD', - bank_name: provider_bank, - merchant_tx_id: order.public_id.to_s, - merchant_client_id: "#{Rails.env}_user_id_#{order.user_id}" - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def transaction_valid?(transaction) - amount_confirmed = transaction.dig('tx', 'in_amount_confirmed') - amount_confirmed.to_f == invoice.amount.to_f || amount_confirmed == '0' - end + def invoice_p2p_params + { + fiat_currency: 'RUB', + fiat_amount: invoice.amount.to_f.to_s, + crypto_currency: 'USDT', + payment_method: 'BANK_CARD', + bank_name: provider_bank, + merchant_tx_id: order.public_id.to_s, + merchant_client_id: "#{Rails.env}_user_id_#{order.user_id}" + } + end - def provider_bank - @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank - end + def transaction_valid?(transaction) + amount_confirmed = transaction.dig('tx', 'in_amount_confirmed') + amount_confirmed.to_f == invoice.amount.to_f || amount_confirmed == '0' + end + + def provider_bank + @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank + end - def client - @client ||= Client.new(api_key: api_key) + def client + @client ||= Client.new(api_key: api_key) + end end end end diff --git a/lib/payment_services/x_pay_pro_virtual/client.rb b/lib/payment_services/x_pay_pro_virtual/client.rb index 70f758ec..d89c411c 100644 --- a/lib/payment_services/x_pay_pro_virtual/client.rb +++ b/lib/payment_services/x_pay_pro_virtual/client.rb @@ -1,39 +1,42 @@ # frozen_string_literal: true -class PaymentServices::XPayProVirtual - class Client < ::PaymentServices::Base::Client - API_URL = 'https://api.xpaypro.dev/v1/merchant-api' - def initialize(api_key:) - @api_key = api_key - end +module PaymentServices + class XPayProVirtual + class Client < ::PaymentServices::Base::Client + API_URL = 'https://api.xpaypro.dev/v1/merchant-api' - def create_invoice(params:) - safely_parse http_request( - url: "#{API_URL}/txs/p2p/invoice", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end + def initialize(api_key:) + @api_key = api_key + end - def transaction(deposit_id:) - safely_parse http_request( - url: "#{API_URL}/txs/#{deposit_id}", - method: :GET, - headers: build_headers - ) - end + def create_invoice(params:) + safely_parse http_request( + url: "#{API_URL}/txs/p2p/invoice", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end + + def transaction(deposit_id:) + safely_parse http_request( + url: "#{API_URL}/txs/#{deposit_id}", + method: :GET, + headers: build_headers + ) + end - private + private - attr_reader :api_key + attr_reader :api_key - def build_headers - { - 'Content-Type' => 'application/json', - 'Authorization' => "Bearer #{api_key}" - } + def build_headers + { + 'Content-Type' => 'application/json', + 'Authorization' => "Bearer #{api_key}" + } + end end end end diff --git a/lib/payment_services/x_pay_pro_virtual/invoice.rb b/lib/payment_services/x_pay_pro_virtual/invoice.rb index e55321d8..0e23fba5 100644 --- a/lib/payment_services/x_pay_pro_virtual/invoice.rb +++ b/lib/payment_services/x_pay_pro_virtual/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::XPayProVirtual - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATE = 'TX_SUCCESS' - FAILED_PROVIDER_STATES = %w(TX_CANCELLED TX_EXPIRED) - self.table_name = 'xpaypro_virtual_invoices' +module PaymentServices + class XPayProVirtual + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATE = 'TX_SUCCESS' + FAILED_PROVIDER_STATES = %w(TX_CANCELLED TX_EXPIRED) - monetize :amount_cents, as: :amount + self.table_name = 'xpaypro_virtual_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state == SUCCESS_PROVIDER_STATE - end + private + + def provider_succeed? + provider_state == SUCCESS_PROVIDER_STATE + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/x_pay_pro_virtual/invoicer.rb b/lib/payment_services/x_pay_pro_virtual/invoicer.rb index f7f83454..aad1ad27 100644 --- a/lib/payment_services/x_pay_pro_virtual/invoicer.rb +++ b/lib/payment_services/x_pay_pro_virtual/invoicer.rb @@ -3,70 +3,73 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::XPayProVirtual - class Invoicer < ::PaymentServices::Base::Invoicer - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - response = client.create_invoice(params: invoice_p2p_params) - raise response['message'] if response['code'] - invoice.update!( - deposit_id: response.dig('tx', 'tx_id'), - rate: response.dig('tx', 'rate').to_f - ) - PaymentServices::Base::Wallet.new( - address: response.dig('tx', 'payment_requisite'), - name: nil, - memo: response.dig('tx', 'payment_system').downcase.capitalize - ) - end +module PaymentServices + class XPayProVirtual + class Invoicer < ::PaymentServices::Base::Invoicer + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + response = client.create_invoice(params: invoice_p2p_params) + raise response['message'] if response['code'] - def create_invoice(money) - invoice - end + invoice.update!( + deposit_id: response.dig('tx', 'tx_id'), + rate: response.dig('tx', 'rate').to_f + ) + PaymentServices::Base::Wallet.new( + address: response.dig('tx', 'payment_requisite'), + name: nil, + memo: response.dig('tx', 'payment_system').downcase.capitalize + ) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.transaction(deposit_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction.dig('tx', 'tx_status')) if transaction_valid?(transaction) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(deposit_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction.dig('tx', 'tx_status')) if transaction_valid?(transaction) + end - private + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - end + private - def invoice_p2p_params - { - fiat_currency: 'RUB', - fiat_amount: invoice.amount.to_f.to_s, - crypto_currency: 'USDT', - payment_method: 'BANK_ACCOUNT', - bank_name: provider_bank, - merchant_tx_id: order.public_id.to_s, - merchant_client_id: "#{Rails.env}_user_id_#{order.user_id}" - } - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + end - def transaction_valid?(transaction) - amount_confirmed = transaction.dig('tx', 'in_amount_confirmed') - amount_confirmed.to_f == invoice.amount.to_f || amount_confirmed == '0' - end + def invoice_p2p_params + { + fiat_currency: 'RUB', + fiat_amount: invoice.amount.to_f.to_s, + crypto_currency: 'USDT', + payment_method: 'BANK_ACCOUNT', + bank_name: provider_bank, + merchant_tx_id: order.public_id.to_s, + merchant_client_id: "#{Rails.env}_user_id_#{order.user_id}" + } + end - def provider_bank - @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank - end + def transaction_valid?(transaction) + amount_confirmed = transaction.dig('tx', 'in_amount_confirmed') + amount_confirmed.to_f == invoice.amount.to_f || amount_confirmed == '0' + end + + def provider_bank + @provider_bank ||= PaymentServices::Base::P2pBankResolver.new(adapter: self).card_bank + end - def client - @client ||= Client.new(api_key: api_key) + def client + @client ||= Client.new(api_key: api_key) + end end end end diff --git a/lib/payment_services/yandex_money/invoice.rb b/lib/payment_services/yandex_money/invoice.rb index c9555f61..89db73bb 100644 --- a/lib/payment_services/yandex_money/invoice.rb +++ b/lib/payment_services/yandex_money/invoice.rb @@ -2,7 +2,10 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::YandexMoney - class Invoice + +module PaymentServices + class YandexMoney + class Invoice + end end end diff --git a/lib/payment_services/yandex_money/invoicer.rb b/lib/payment_services/yandex_money/invoicer.rb index f803895e..3c5dfef5 100644 --- a/lib/payment_services/yandex_money/invoicer.rb +++ b/lib/payment_services/yandex_money/invoicer.rb @@ -4,27 +4,30 @@ require_relative 'invoice' -class PaymentServices::YandexMoney - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money); end - def invoice_form_data - description = I18n.t('payment_systems.personal_payment', order_id: order.public_id) - { - url: 'https://money.yandex.ru/quickpay/confirm.xml', - method: 'POST', - target: '_blank', - inputs: { - receiver: order.income_wallet.account, - formcomment: description, - shortvalue: description, - targets: description, - label: order.public_id, - sum: order.invoice_money.to_f, - paymentType: 'PC', - 'quickpay-form' => 'shop' +module PaymentServices + class YandexMoney + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money); end + + def invoice_form_data + description = I18n.t('payment_systems.personal_payment', order_id: order.public_id) + { + url: 'https://money.yandex.ru/quickpay/confirm.xml', + method: 'POST', + target: '_blank', + inputs: { + receiver: order.income_wallet.account, + formcomment: description, + shortvalue: description, + targets: description, + label: order.public_id, + sum: order.invoice_money.to_f, + paymentType: 'PC', + 'quickpay-form' => 'shop' + } } - } + end end end end diff --git a/lib/payment_services/yandex_money_payment_card/invoice.rb b/lib/payment_services/yandex_money_payment_card/invoice.rb index 66cc1427..ada4c332 100644 --- a/lib/payment_services/yandex_money_payment_card/invoice.rb +++ b/lib/payment_services/yandex_money_payment_card/invoice.rb @@ -2,7 +2,10 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex -class PaymentServices::YandexMoneyPaymentCard - class Invoice + +module PaymentServices + class YandexMoneyPaymentCard + class Invoice + end end end diff --git a/lib/payment_services/yandex_money_payment_card/invoicer.rb b/lib/payment_services/yandex_money_payment_card/invoicer.rb index 715116aa..443b0d6b 100644 --- a/lib/payment_services/yandex_money_payment_card/invoicer.rb +++ b/lib/payment_services/yandex_money_payment_card/invoicer.rb @@ -4,27 +4,30 @@ require_relative 'invoice' -class PaymentServices::YandexMoneyPaymentCard - class Invoicer < ::PaymentServices::Base::Invoicer - def create_invoice(money); end - def invoice_form_data - description = I18n.t('payment_systems.personal_payment', order_id: order.public_id) - { - url: 'https://money.yandex.ru/quickpay/confirm.xml', - method: 'POST', - target: '_blank', - inputs: { - receiver: order.income_wallet.account, - formcomment: description, - shortvalue: description, - targets: description, - label: order.public_id, - sum: order.invoice_money.to_f, - paymentType: 'AC', - 'quickpay-form' => 'shop' +module PaymentServices + class YandexMoneyPaymentCard + class Invoicer < ::PaymentServices::Base::Invoicer + def create_invoice(money); end + + def invoice_form_data + description = I18n.t('payment_systems.personal_payment', order_id: order.public_id) + { + url: 'https://money.yandex.ru/quickpay/confirm.xml', + method: 'POST', + target: '_blank', + inputs: { + receiver: order.income_wallet.account, + formcomment: description, + shortvalue: description, + targets: description, + label: order.public_id, + sum: order.invoice_money.to_f, + paymentType: 'AC', + 'quickpay-form' => 'shop' + } } - } + end end end end diff --git a/lib/payment_services/your_payments/client.rb b/lib/payment_services/your_payments/client.rb index 202aded8..022a575a 100644 --- a/lib/payment_services/your_payments/client.rb +++ b/lib/payment_services/your_payments/client.rb @@ -1,75 +1,78 @@ # frozen_string_literal: true -class PaymentServices::YourPayments - class Client < ::PaymentServices::Base::Client - API_URL = 'https://yourpayment.pro/api' - def initialize(api_key:, secret_key:) - @api_key = api_key - @secret_key = secret_key - end +module PaymentServices + class YourPayments + class Client < ::PaymentServices::Base::Client + API_URL = 'https://yourpayment.pro/api' - def create_provider_transaction(params:) - params.merge!(merchant_id: api_key) - safely_parse http_request( - url: "#{API_URL}/merchant-api/create-order", - method: :POST, - body: params.merge(signature: build_signature(params)).to_json, - headers: build_headers - ) - end + def initialize(api_key:, secret_key:) + @api_key = api_key + @secret_key = secret_key + end - def request_payment_details(params:) - safely_parse http_request( - url: "#{API_URL}/public/execute", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end + def create_provider_transaction(params:) + params.merge!(merchant_id: api_key) + safely_parse http_request( + url: "#{API_URL}/merchant-api/create-order", + method: :POST, + body: params.merge(signature: build_signature(params)).to_json, + headers: build_headers + ) + end - def payment_details(invoice_id:) - params = { order_id: invoice_id } - safely_parse http_request( - url: "#{API_URL}/public/order-details", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end + def request_payment_details(params:) + safely_parse http_request( + url: "#{API_URL}/public/execute", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end - def confirm_payment(deposit_id:) - params = { order_id: deposit_id } - safely_parse http_request( - url: "#{API_URL}/public/mark-paid", - method: :POST, - body: params.to_json, - headers: build_headers - ) - end + def payment_details(invoice_id:) + params = { order_id: invoice_id } + safely_parse http_request( + url: "#{API_URL}/public/order-details", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end - def transaction(transaction_id:) - params = { merchant_id: api_key, order_id: transaction_id } - safely_parse http_request( - url: "#{API_URL}/merchant-api/get-order", - method: :POST, - body: params.merge(signature: build_signature(params)).to_json, - headers: build_headers - ) - end + def confirm_payment(deposit_id:) + params = { order_id: deposit_id } + safely_parse http_request( + url: "#{API_URL}/public/mark-paid", + method: :POST, + body: params.to_json, + headers: build_headers + ) + end - private + def transaction(transaction_id:) + params = { merchant_id: api_key, order_id: transaction_id } + safely_parse http_request( + url: "#{API_URL}/merchant-api/get-order", + method: :POST, + body: params.merge(signature: build_signature(params)).to_json, + headers: build_headers + ) + end - attr_reader :api_key, :secret_key + private - def build_signature(params) - Digest::MD5.hexdigest("#{secret_key}+#{params.to_json}") - end + attr_reader :api_key, :secret_key + + def build_signature(params) + Digest::MD5.hexdigest("#{secret_key}+#{params.to_json}") + end - def build_headers - { - 'Content-Type' => 'application/json' - } + def build_headers + { + 'Content-Type' => 'application/json' + } + end end end end diff --git a/lib/payment_services/your_payments/invoice.rb b/lib/payment_services/your_payments/invoice.rb index 8c2f59cf..dc2f49f5 100644 --- a/lib/payment_services/your_payments/invoice.rb +++ b/lib/payment_services/your_payments/invoice.rb @@ -1,22 +1,25 @@ # frozen_string_literal: true -class PaymentServices::YourPayments - class Invoice < ::PaymentServices::Base::FiatInvoice - SUCCESS_PROVIDER_STATES = %w(FINISHED_SUCCESS FINISHED_SUCCESS_RECALC) - FAILED_PROVIDER_STATES = %w(FINISHED_REJECTED FINISHED_EXPIRED FINISHED_CANCELED) - self.table_name = 'your_payments_invoices' +module PaymentServices + class YourPayments + class Invoice < ::PaymentServices::Base::FiatInvoice + SUCCESS_PROVIDER_STATES = %w(FINISHED_SUCCESS FINISHED_SUCCESS_RECALC) + FAILED_PROVIDER_STATES = %w(FINISHED_REJECTED FINISHED_EXPIRED FINISHED_CANCELED) - monetize :amount_cents, as: :amount + self.table_name = 'your_payments_invoices' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state.in? SUCCESS_PROVIDER_STATES - end + private + + def provider_succeed? + provider_state.in? SUCCESS_PROVIDER_STATES + end - def provider_failed? - provider_state.in? FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/your_payments/invoicer.rb b/lib/payment_services/your_payments/invoicer.rb index e3792915..84f6cffe 100644 --- a/lib/payment_services/your_payments/invoicer.rb +++ b/lib/payment_services/your_payments/invoicer.rb @@ -3,105 +3,108 @@ require_relative 'invoice' require_relative 'client' -class PaymentServices::YourPayments - class Invoicer < ::PaymentServices::Base::Invoicer - PROVIDER_REQUISITES_FOUND_STATE = 'TRADER_ACCEPTED' - PROVIDER_REQUEST_RETRIES = 3 - CARD_METHOD_TYPE = 'card_number' - SBP_METHOD_TYPE = 'phone_number' - Error = Class.new StandardError +module PaymentServices + class YourPayments + class Invoicer < ::PaymentServices::Base::Invoicer + PROVIDER_REQUISITES_FOUND_STATE = 'TRADER_ACCEPTED' + PROVIDER_REQUEST_RETRIES = 3 + CARD_METHOD_TYPE = 'card_number' + SBP_METHOD_TYPE = 'phone_number' - def prepare_invoice_and_get_wallet!(currency:, token_network:) - create_invoice! - card_number, card_holder, bank_name = fetch_card_details! + Error = Class.new StandardError - PaymentServices::Base::Wallet.new(address: card_number, name: card_holder, memo: bank_name) - end + def prepare_invoice_and_get_wallet!(currency:, token_network:) + create_invoice! + card_number, card_holder, bank_name = fetch_card_details! - def create_invoice(money) - invoice - end + PaymentServices::Base::Wallet.new(address: card_number, name: card_holder, memo: bank_name) + end - def async_invoice_state_updater? - true - end + def create_invoice(money) + invoice + end - def update_invoice_state! - transaction = client.transaction(transaction_id: invoice.deposit_id) - invoice.update_state_by_provider(transaction['status']) - end + def async_invoice_state_updater? + true + end - def invoice - @invoice ||= Invoice.find_by(order_public_id: order.public_id) - end + def update_invoice_state! + transaction = client.transaction(transaction_id: invoice.deposit_id) + invoice.update_state_by_provider(transaction['status']) + end - def confirm_payment - client.confirm_payment(deposit_id: invoice.deposit_id) - end + def invoice + @invoice ||= Invoice.find_by(order_public_id: order.public_id) + end - private - - delegate :card_bank, :sbp_bank, :sbp?, to: :resolver - delegate :income_payment_system, :income_unk, to: :order - delegate :currency, to: :income_payment_system - - def invoice_params - { - type: 'buy', - amount: invoice.amount_cents, - currency: currency.to_s, - method_type: method_type, - customer_id: order.user_id.to_s, - invoice_id: order.public_id.to_s - } - end + def confirm_payment + client.confirm_payment(deposit_id: invoice.deposit_id) + end - def create_invoice! - Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) - response = client.create_provider_transaction(params: invoice_params) + private + + delegate :card_bank, :sbp_bank, :sbp?, to: :resolver + delegate :income_payment_system, :income_unk, to: :order + delegate :currency, to: :income_payment_system + + def invoice_params + { + type: 'buy', + amount: invoice.amount_cents, + currency: currency.to_s, + method_type: method_type, + customer_id: order.user_id.to_s, + invoice_id: order.public_id.to_s + } + end - raise Error, "Can't create invoice: #{response}" unless response['order_id'] - invoice.update!(deposit_id: response['order_id']) - end + def create_invoice! + Invoice.create!(amount: order.calculated_income_money, order_public_id: order.public_id) + response = client.create_provider_transaction(params: invoice_params) - def fetch_card_details! - status = request_trader - raise Error, 'Нет доступных реквизитов для оплаты' unless status == PROVIDER_REQUISITES_FOUND_STATE + raise Error, "Can't create invoice: #{response}" unless response['order_id'] + invoice.update!(deposit_id: response['order_id']) + end - payment_details = client.payment_details(invoice_id: invoice.deposit_id) - number = payment_details['card'] - number = prepare_phone_number(number) if sbp? + def fetch_card_details! + status = request_trader + raise Error, 'Нет доступных реквизитов для оплаты' unless status == PROVIDER_REQUISITES_FOUND_STATE - [number, payment_details['holder'], payment_details['bank']] - end + payment_details = client.payment_details(invoice_id: invoice.deposit_id) + number = payment_details['card'] + number = prepare_phone_number(number) if sbp? - def request_trader - PROVIDER_REQUEST_RETRIES.times do - sleep 2 + [number, payment_details['holder'], payment_details['bank']] + end - params = { order_id: invoice.deposit_id } - params[:bank] = sbp_bank if sbp? && sbp_bank.present? - params[:bank] = card_bank unless sbp? - status = client.request_payment_details(params: params) - break status if status == PROVIDER_REQUISITES_FOUND_STATE + def request_trader + PROVIDER_REQUEST_RETRIES.times do + sleep 2 + + params = { order_id: invoice.deposit_id } + params[:bank] = sbp_bank if sbp? && sbp_bank.present? + params[:bank] = card_bank unless sbp? + status = client.request_payment_details(params: params) + break status if status == PROVIDER_REQUISITES_FOUND_STATE + end end - end - def resolver - @resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) - end + def resolver + @resolver ||= PaymentServices::Base::P2pBankResolver.new(adapter: self) + end - def method_type - sbp? ? SBP_METHOD_TYPE : CARD_METHOD_TYPE - end + def method_type + sbp? ? SBP_METHOD_TYPE : CARD_METHOD_TYPE + end - def prepare_phone_number(provider_phone_number) - "#{provider_phone_number[0..1]} (#{provider_phone_number[3..5]}) #{provider_phone_number[7..9]}-#{provider_phone_number[11..12]}-#{provider_phone_number[14..15]}" - end + def prepare_phone_number(provider_phone_number) + "#{provider_phone_number[0..1]} (#{provider_phone_number[3..5]}) #{provider_phone_number[7..9]}-#{provider_phone_number[11..12]}-#{provider_phone_number[14..15]}" + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end diff --git a/lib/payment_services/your_payments/payout.rb b/lib/payment_services/your_payments/payout.rb index 4cecb232..2ce3cdf4 100644 --- a/lib/payment_services/your_payments/payout.rb +++ b/lib/payment_services/your_payments/payout.rb @@ -1,19 +1,22 @@ # frozen_string_literal: true -class PaymentServices::YourPayments - class Payout < ::PaymentServices::Base::FiatPayout - self.table_name = 'your_payments_payouts' - monetize :amount_cents, as: :amount +module PaymentServices + class YourPayments + class Payout < ::PaymentServices::Base::FiatPayout + self.table_name = 'your_payments_payouts' - private + monetize :amount_cents, as: :amount - def provider_succeed? - provider_state.in? Invoice::SUCCESS_PROVIDER_STATES - end + private + + def provider_succeed? + provider_state.in? Invoice::SUCCESS_PROVIDER_STATES + end - def provider_failed? - provider_state.in? Invoice::FAILED_PROVIDER_STATES + def provider_failed? + provider_state.in? Invoice::FAILED_PROVIDER_STATES + end end end end diff --git a/lib/payment_services/your_payments/payout_adapter.rb b/lib/payment_services/your_payments/payout_adapter.rb index 3988e91b..38f5d29b 100644 --- a/lib/payment_services/your_payments/payout_adapter.rb +++ b/lib/payment_services/your_payments/payout_adapter.rb @@ -3,73 +3,76 @@ require_relative 'payout' require_relative 'client' -class PaymentServices::YourPayments - class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter - Error = Class.new StandardError - - def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) - make_payout( - amount: amount, - destination_account: destination_account, - order_payout_id: order_payout_id - ) - end - def refresh_status!(payout_id) - payout = Payout.find(payout_id) - return if payout.pending? +module PaymentServices + class YourPayments + class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter + Error = Class.new StandardError - transaction = client.transaction(transaction_id: payout.withdrawal_id) - payout.update_state_by_provider(transaction['status']) - transaction - end + def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:, order_payout_id:) + make_payout( + amount: amount, + destination_account: destination_account, + order_payout_id: order_payout_id + ) + end - private + def refresh_status!(payout_id) + payout = Payout.find(payout_id) + return if payout.pending? - attr_reader :payout + transaction = client.transaction(transaction_id: payout.withdrawal_id) + payout.update_state_by_provider(transaction['status']) + transaction + end - def make_payout(amount:, destination_account:, order_payout_id:) - @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) - response = client.create_provider_transaction(params: payout_params) - raise Error, "Can't create payout: #{response}" unless response['order_id'] + private - payout.pay!(withdrawal_id: response['order_id']) - end + attr_reader :payout + + def make_payout(amount:, destination_account:, order_payout_id:) + @payout = Payout.create!(amount: amount, destination_account: destination_account, order_payout_id: order_payout_id) + response = client.create_provider_transaction(params: payout_params) + raise Error, "Can't create payout: #{response}" unless response['order_id'] + + payout.pay!(withdrawal_id: response['order_id']) + end - def payout_params - { - type: 'sell', - amount: payout.amount_cents, - currency: payout.amount_currency.to_s, - method_type: method_type, - customer_id: order.user_id.to_s, - invoice_id: order.public_id.to_s, - sell_details: { - receiver: payout.destination_account, - bank: provider_bank + def payout_params + { + type: 'sell', + amount: payout.amount_cents, + currency: payout.amount_currency.to_s, + method_type: method_type, + customer_id: order.user_id.to_s, + invoice_id: order.public_id.to_s, + sell_details: { + receiver: payout.destination_account, + bank: provider_bank + } } - } - end + end - def provider_bank - resolver = PaymentServices::Base::P2pBankResolver.new(adapter: self) - sbp_payment? ? resolver.sbp_bank : resolver.card_bank - end + def provider_bank + resolver = PaymentServices::Base::P2pBankResolver.new(adapter: self) + sbp_payment? ? resolver.sbp_bank : resolver.card_bank + end - def method_type - sbp_payment? ? Invoicer::SBP_METHOD_TYPE : Invoicer::CARD_METHOD_TYPE - end + def method_type + sbp_payment? ? Invoicer::SBP_METHOD_TYPE : Invoicer::CARD_METHOD_TYPE + end - def sbp_payment? - @sbp_payment ||= order.outcome_unk.present? - end + def sbp_payment? + @sbp_payment ||= order.outcome_unk.present? + end - def order - @order ||= OrderPayout.find(payout.order_payout_id).order - end + def order + @order ||= OrderPayout.find(payout.order_payout_id).order + end - def client - @client ||= Client.new(api_key: api_key, secret_key: api_secret) + def client + @client ||= Client.new(api_key: api_key, secret_key: api_secret) + end end end end From 6c9193d53b5131ac0dfd2a842903bbb9007335e7 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 17:09:52 +0200 Subject: [PATCH 02/12] fix: remove extra blank lines to comply with RuboCop Layout/EmptyLines --- lib/payment_services/adv_cash/client.rb | 1 - lib/payment_services/adv_cash/invoice.rb | 1 - lib/payment_services/adv_cash/invoicer.rb | 1 - lib/payment_services/adv_cash/payout.rb | 1 - lib/payment_services/adv_cash/payout_adapter.rb | 1 - lib/payment_services/ali_kassa/client.rb | 1 - lib/payment_services/ali_kassa/invoice.rb | 1 - lib/payment_services/ali_kassa/invoicer.rb | 1 - lib/payment_services/ali_kassa_peer_to_peer/invoice.rb | 1 - lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb | 1 - lib/payment_services/any_money/client.rb | 1 - lib/payment_services/any_money/invoice.rb | 1 - lib/payment_services/any_money/invoicer.rb | 1 - lib/payment_services/any_money/payout.rb | 1 - lib/payment_services/any_money/payout_adapter.rb | 1 - lib/payment_services/any_pay/client.rb | 1 - lib/payment_services/any_pay/invoice.rb | 1 - lib/payment_services/any_pay/invoicer.rb | 1 - lib/payment_services/any_pay/payout.rb | 1 - lib/payment_services/any_pay/payout_adapter.rb | 1 - lib/payment_services/appex_money/client.rb | 1 - lib/payment_services/appex_money/payout.rb | 1 - lib/payment_services/appex_money/payout_adapter.rb | 1 - lib/payment_services/best_api/client.rb | 1 - lib/payment_services/best_api/invoice.rb | 1 - lib/payment_services/best_api/invoicer.rb | 1 - lib/payment_services/binance/client.rb | 1 - lib/payment_services/binance/invoice.rb | 1 - lib/payment_services/binance/invoicer.rb | 1 - lib/payment_services/binance/payout.rb | 1 - lib/payment_services/binance/payout_adapter.rb | 1 - lib/payment_services/block_io/client.rb | 1 - lib/payment_services/block_io/invoice.rb | 1 - lib/payment_services/block_io/invoicer.rb | 1 - lib/payment_services/block_io/payout.rb | 1 - lib/payment_services/block_io/transaction.rb | 1 - lib/payment_services/blockchair/blockchain.rb | 1 - lib/payment_services/blockchair/client.rb | 1 - lib/payment_services/blockchair/invoice.rb | 1 - lib/payment_services/blockchair/invoicer.rb | 1 - lib/payment_services/blockchair/transaction.rb | 1 - lib/payment_services/blockchair/transaction_matcher.rb | 1 - lib/payment_services/bovapay/client.rb | 1 - lib/payment_services/bovapay/invoice.rb | 1 - lib/payment_services/bovapay/invoicer.rb | 1 - lib/payment_services/bovapay/payout.rb | 1 - lib/payment_services/bovapay/payout_adapter.rb | 1 - lib/payment_services/bridgex/client.rb | 1 - lib/payment_services/bridgex/invoice.rb | 1 - lib/payment_services/bridgex/invoicer.rb | 1 - lib/payment_services/coin_payments_hub/client.rb | 1 - lib/payment_services/coin_payments_hub/currency_repository.rb | 1 - lib/payment_services/coin_payments_hub/invoice.rb | 1 - lib/payment_services/coin_payments_hub/invoicer.rb | 1 - lib/payment_services/coin_payments_hub/transaction.rb | 1 - lib/payment_services/crypto_apis/clients/base_client.rb | 1 - lib/payment_services/crypto_apis/clients/dash_client.rb | 1 - lib/payment_services/crypto_apis/clients/ethereum_client.rb | 1 - lib/payment_services/crypto_apis/clients/omni_client.rb | 1 - lib/payment_services/crypto_apis/invoice.rb | 1 - lib/payment_services/crypto_apis/invoicer.rb | 1 - lib/payment_services/crypto_apis/payout.rb | 1 - lib/payment_services/crypto_apis/payout_adapter.rb | 1 - lib/payment_services/crypto_apis/payout_clients/base_client.rb | 1 - lib/payment_services/crypto_apis/payout_clients/dash_client.rb | 1 - .../crypto_apis/payout_clients/ethereum_client.rb | 1 - lib/payment_services/crypto_apis/payout_clients/omni_client.rb | 1 - lib/payment_services/crypto_apis_v2/blockchain.rb | 1 - lib/payment_services/crypto_apis_v2/client.rb | 1 - lib/payment_services/crypto_apis_v2/invoice.rb | 1 - lib/payment_services/crypto_apis_v2/invoicer.rb | 1 - lib/payment_services/crypto_apis_v2/payout.rb | 1 - lib/payment_services/crypto_apis_v2/payout_adapter.rb | 1 - lib/payment_services/crypto_apis_v2/transaction.rb | 1 - lib/payment_services/crypto_apis_v2/transaction_repository.rb | 1 - lib/payment_services/cryptomus/client.rb | 1 - lib/payment_services/cryptomus/invoice.rb | 1 - lib/payment_services/cryptomus/invoicer.rb | 1 - lib/payment_services/cryptomus/payout.rb | 1 - lib/payment_services/cryptomus/payout_adapter.rb | 1 - lib/payment_services/erapay/client.rb | 1 - lib/payment_services/erapay/invoice.rb | 1 - lib/payment_services/erapay/invoicer.rb | 1 - lib/payment_services/ex_pay/client.rb | 1 - lib/payment_services/ex_pay/invoice.rb | 1 - lib/payment_services/ex_pay/invoicer.rb | 1 - lib/payment_services/ex_pay/payout.rb | 1 - lib/payment_services/ex_pay/payout_adapter.rb | 1 - lib/payment_services/exmo/client.rb | 1 - lib/payment_services/exmo/invoice.rb | 1 - lib/payment_services/exmo/invoicer.rb | 1 - lib/payment_services/exmo/payout.rb | 1 - lib/payment_services/exmo/payout_adapter.rb | 1 - lib/payment_services/exmo/transaction.rb | 1 - lib/payment_services/ff/client.rb | 1 - lib/payment_services/ff/invoice.rb | 1 - lib/payment_services/ff/invoicer.rb | 1 - lib/payment_services/ff/payout.rb | 1 - lib/payment_services/ff/payout_adapter.rb | 1 - lib/payment_services/ff/transaction.rb | 1 - lib/payment_services/fire_kassa/client.rb | 1 - lib/payment_services/fire_kassa/invoice.rb | 1 - lib/payment_services/fire_kassa/invoicer.rb | 1 - lib/payment_services/just_pays/client.rb | 1 - lib/payment_services/just_pays/invoice.rb | 1 - lib/payment_services/just_pays/invoicer.rb | 1 - lib/payment_services/kuna/client.rb | 1 - lib/payment_services/kuna/invoice.rb | 1 - lib/payment_services/kuna/invoicer.rb | 1 - lib/payment_services/kuna/payout.rb | 1 - lib/payment_services/kuna/payout_adapter.rb | 1 - lib/payment_services/liquid/client.rb | 1 - lib/payment_services/liquid/invoice.rb | 1 - lib/payment_services/liquid/invoicer.rb | 1 - lib/payment_services/liquid/payout.rb | 1 - lib/payment_services/liquid/payout_adapter.rb | 1 - lib/payment_services/manual_by_group/invoicer.rb | 1 - lib/payment_services/master_processing/client.rb | 1 - lib/payment_services/master_processing/invoice.rb | 1 - lib/payment_services/master_processing/invoicer.rb | 1 - lib/payment_services/master_processing/payout.rb | 1 - lib/payment_services/master_processing/payout_adapter.rb | 1 - lib/payment_services/master_processing/response.rb | 1 - lib/payment_services/merchant_alikassa/client.rb | 1 - lib/payment_services/merchant_alikassa/invoice.rb | 1 - lib/payment_services/merchant_alikassa/invoicer.rb | 1 - lib/payment_services/merchant_alikassa/payout.rb | 1 - lib/payment_services/merchant_alikassa/payout_adapter.rb | 1 - lib/payment_services/merchant_alikassa_virtual/client.rb | 1 - lib/payment_services/merchant_alikassa_virtual/invoice.rb | 1 - lib/payment_services/merchant_alikassa_virtual/invoicer.rb | 1 - lib/payment_services/obmenka/client.rb | 1 - lib/payment_services/obmenka/invoice.rb | 1 - lib/payment_services/obmenka/invoicer.rb | 1 - lib/payment_services/obmenka/payout.rb | 1 - lib/payment_services/obmenka/payout_adapter.rb | 1 - lib/payment_services/oko_otc/client.rb | 1 - lib/payment_services/oko_otc/payout.rb | 1 - lib/payment_services/oko_otc/payout_adapter.rb | 1 - lib/payment_services/one_crypto/client.rb | 1 - lib/payment_services/one_crypto/invoice.rb | 1 - lib/payment_services/one_crypto/invoicer.rb | 1 - lib/payment_services/one_crypto/payout.rb | 1 - lib/payment_services/one_crypto/payout_adapter.rb | 1 - lib/payment_services/one_crypto/transaction.rb | 1 - lib/payment_services/panda_pay/client.rb | 1 - lib/payment_services/panda_pay/invoice.rb | 1 - lib/payment_services/panda_pay/invoicer.rb | 1 - lib/payment_services/pay_for_u/client.rb | 1 - lib/payment_services/pay_for_u/invoice.rb | 1 - lib/payment_services/pay_for_u/invoicer.rb | 1 - lib/payment_services/pay_for_u_h2h/client.rb | 1 - lib/payment_services/pay_for_u_h2h/invoice.rb | 1 - lib/payment_services/pay_for_u_h2h/invoicer.rb | 1 - lib/payment_services/paycraft/client.rb | 1 - lib/payment_services/paycraft/invoice.rb | 1 - lib/payment_services/paycraft/invoicer.rb | 1 - lib/payment_services/paycraft/payout.rb | 1 - lib/payment_services/paycraft/payout_adapter.rb | 1 - lib/payment_services/paycraft_virtual/client.rb | 1 - lib/payment_services/paycraft_virtual/invoice.rb | 1 - lib/payment_services/paycraft_virtual/invoicer.rb | 1 - lib/payment_services/payeer/client.rb | 1 - lib/payment_services/payeer/invoice.rb | 1 - lib/payment_services/payeer/invoicer.rb | 1 - lib/payment_services/payeer/payout.rb | 1 - lib/payment_services/payeer/payout_adapter.rb | 1 - lib/payment_services/paylama/client.rb | 1 - lib/payment_services/paylama/currency_repository.rb | 1 - lib/payment_services/paylama/invoice.rb | 1 - lib/payment_services/paylama/invoicer.rb | 1 - lib/payment_services/paylama/payout.rb | 1 - lib/payment_services/paylama/payout_adapter.rb | 1 - lib/payment_services/paylama_crypto/invoice.rb | 1 - lib/payment_services/paylama_crypto/invoicer.rb | 1 - lib/payment_services/paylama_crypto/payout.rb | 1 - lib/payment_services/paylama_crypto/payout_adapter.rb | 1 - lib/payment_services/paylama_crypto/transaction.rb | 1 - lib/payment_services/paylama_p2p/client.rb | 1 - lib/payment_services/paylama_p2p/invoice.rb | 1 - lib/payment_services/paylama_p2p/invoicer.rb | 1 - lib/payment_services/paylama_sbp/client.rb | 1 - lib/payment_services/paylama_sbp/invoice.rb | 1 - lib/payment_services/paylama_sbp/invoicer.rb | 1 - lib/payment_services/perfect_money/client.rb | 1 - lib/payment_services/perfect_money/invoice.rb | 1 - lib/payment_services/perfect_money/invoicer.rb | 1 - lib/payment_services/perfect_money/payout.rb | 1 - lib/payment_services/perfect_money/payout_adapter.rb | 1 - lib/payment_services/qiwi/client.rb | 1 - lib/payment_services/qiwi/importer.rb | 1 - lib/payment_services/qiwi/invoice.rb | 1 - lib/payment_services/qiwi/invoicer.rb | 1 - lib/payment_services/qiwi/payment.rb | 1 - lib/payment_services/rbk/client.rb | 1 - lib/payment_services/rbk/customer.rb | 1 - lib/payment_services/rbk/customer_client.rb | 1 - lib/payment_services/rbk/identity.rb | 1 - lib/payment_services/rbk/identity_client.rb | 1 - lib/payment_services/rbk/invoice.rb | 1 - lib/payment_services/rbk/invoice_client.rb | 1 - lib/payment_services/rbk/invoicer.rb | 1 - lib/payment_services/rbk/payment.rb | 1 - lib/payment_services/rbk/payment_card.rb | 1 - lib/payment_services/rbk/payment_client.rb | 1 - lib/payment_services/rbk/payout.rb | 1 - lib/payment_services/rbk/payout_client.rb | 1 - lib/payment_services/rbk/payout_destination.rb | 1 - lib/payment_services/rbk/payout_destination_client.rb | 1 - lib/payment_services/rbk/wallet.rb | 1 - lib/payment_services/rbk/wallet_client.rb | 1 - lib/payment_services/transfera/client.rb | 1 - lib/payment_services/transfera/invoice.rb | 1 - lib/payment_services/transfera/invoicer.rb | 1 - lib/payment_services/tronscan/client.rb | 1 - lib/payment_services/tronscan/invoice.rb | 1 - lib/payment_services/tronscan/invoicer.rb | 1 - lib/payment_services/tronscan/transaction.rb | 1 - lib/payment_services/tronscan/transaction_matcher.rb | 1 - lib/payment_services/wallex/client.rb | 1 - lib/payment_services/wallex/invoice.rb | 1 - lib/payment_services/wallex/invoicer.rb | 1 - lib/payment_services/wallex/payout.rb | 1 - lib/payment_services/wallex/payout_adapter.rb | 1 - lib/payment_services/x_pay_pro/client.rb | 1 - lib/payment_services/x_pay_pro/invoice.rb | 1 - lib/payment_services/x_pay_pro/invoicer.rb | 1 - lib/payment_services/x_pay_pro_virtual/client.rb | 1 - lib/payment_services/x_pay_pro_virtual/invoice.rb | 1 - lib/payment_services/x_pay_pro_virtual/invoicer.rb | 1 - lib/payment_services/yandex_money/invoice.rb | 1 - lib/payment_services/yandex_money/invoicer.rb | 1 - lib/payment_services/yandex_money_payment_card/invoice.rb | 1 - lib/payment_services/yandex_money_payment_card/invoicer.rb | 1 - lib/payment_services/your_payments/client.rb | 1 - lib/payment_services/your_payments/invoice.rb | 1 - lib/payment_services/your_payments/invoicer.rb | 1 - lib/payment_services/your_payments/payout.rb | 1 - lib/payment_services/your_payments/payout_adapter.rb | 1 - 239 files changed, 239 deletions(-) diff --git a/lib/payment_services/adv_cash/client.rb b/lib/payment_services/adv_cash/client.rb index bf28d78c..313cdde7 100644 --- a/lib/payment_services/adv_cash/client.rb +++ b/lib/payment_services/adv_cash/client.rb @@ -2,7 +2,6 @@ require 'savon' - module PaymentServices class AdvCash class Client diff --git a/lib/payment_services/adv_cash/invoice.rb b/lib/payment_services/adv_cash/invoice.rb index 17148213..7316e519 100644 --- a/lib/payment_services/adv_cash/invoice.rb +++ b/lib/payment_services/adv_cash/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class AdvCash class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/adv_cash/invoicer.rb b/lib/payment_services/adv_cash/invoicer.rb index 9c3f7cba..01a18a56 100644 --- a/lib/payment_services/adv_cash/invoicer.rb +++ b/lib/payment_services/adv_cash/invoicer.rb @@ -5,7 +5,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class AdvCash class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/adv_cash/payout.rb b/lib/payment_services/adv_cash/payout.rb index 60eebfc4..9c0c29bb 100644 --- a/lib/payment_services/adv_cash/payout.rb +++ b/lib/payment_services/adv_cash/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AdvCash class Payout < ApplicationRecord diff --git a/lib/payment_services/adv_cash/payout_adapter.rb b/lib/payment_services/adv_cash/payout_adapter.rb index bff16372..8a7b67e1 100644 --- a/lib/payment_services/adv_cash/payout_adapter.rb +++ b/lib/payment_services/adv_cash/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class AdvCash class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/ali_kassa/client.rb b/lib/payment_services/ali_kassa/client.rb index 67065cb1..37c0657d 100644 --- a/lib/payment_services/ali_kassa/client.rb +++ b/lib/payment_services/ali_kassa/client.rb @@ -2,7 +2,6 @@ # Copyright (c) 2019 FINFEX https://github.com/finfex - module PaymentServices class AliKassa class Client diff --git a/lib/payment_services/ali_kassa/invoice.rb b/lib/payment_services/ali_kassa/invoice.rb index 0932a3ed..6569053b 100644 --- a/lib/payment_services/ali_kassa/invoice.rb +++ b/lib/payment_services/ali_kassa/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class AliKassa class Invoice < ApplicationRecord diff --git a/lib/payment_services/ali_kassa/invoicer.rb b/lib/payment_services/ali_kassa/invoicer.rb index 4aec427c..4fbfcb3d 100644 --- a/lib/payment_services/ali_kassa/invoicer.rb +++ b/lib/payment_services/ali_kassa/invoicer.rb @@ -5,7 +5,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class AliKassa class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb b/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb index a4f22e6c..2750eab7 100644 --- a/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb +++ b/lib/payment_services/ali_kassa_peer_to_peer/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class AliKassaPeerToPeer class Invoice < ApplicationRecord diff --git a/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb b/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb index 208c5411..b5986944 100644 --- a/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb +++ b/lib/payment_services/ali_kassa_peer_to_peer/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' - module PaymentServices class AliKassaPeerToPeer class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/any_money/client.rb b/lib/payment_services/any_money/client.rb index 2023db95..227b1b4e 100644 --- a/lib/payment_services/any_money/client.rb +++ b/lib/payment_services/any_money/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AnyMoney class Client diff --git a/lib/payment_services/any_money/invoice.rb b/lib/payment_services/any_money/invoice.rb index dd6b8e31..47547613 100644 --- a/lib/payment_services/any_money/invoice.rb +++ b/lib/payment_services/any_money/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class AnyMoney class Invoice < ApplicationRecord diff --git a/lib/payment_services/any_money/invoicer.rb b/lib/payment_services/any_money/invoicer.rb index 7b877995..23c22f63 100644 --- a/lib/payment_services/any_money/invoicer.rb +++ b/lib/payment_services/any_money/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' - module PaymentServices class AnyMoney class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/any_money/payout.rb b/lib/payment_services/any_money/payout.rb index f66749da..5bd25e36 100644 --- a/lib/payment_services/any_money/payout.rb +++ b/lib/payment_services/any_money/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AnyMoney class Payout < ApplicationRecord diff --git a/lib/payment_services/any_money/payout_adapter.rb b/lib/payment_services/any_money/payout_adapter.rb index 5270f2e2..585c8116 100644 --- a/lib/payment_services/any_money/payout_adapter.rb +++ b/lib/payment_services/any_money/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class AnyMoney class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/any_pay/client.rb b/lib/payment_services/any_pay/client.rb index 0cbe7e01..8d4e7111 100644 --- a/lib/payment_services/any_pay/client.rb +++ b/lib/payment_services/any_pay/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AnyPay class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/any_pay/invoice.rb b/lib/payment_services/any_pay/invoice.rb index b817a52f..8e57e9f4 100644 --- a/lib/payment_services/any_pay/invoice.rb +++ b/lib/payment_services/any_pay/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AnyPay class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/any_pay/invoicer.rb b/lib/payment_services/any_pay/invoicer.rb index 940bcd5c..6b4fedc5 100644 --- a/lib/payment_services/any_pay/invoicer.rb +++ b/lib/payment_services/any_pay/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class AnyPay class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/any_pay/payout.rb b/lib/payment_services/any_pay/payout.rb index cb9c47a8..f9640bef 100644 --- a/lib/payment_services/any_pay/payout.rb +++ b/lib/payment_services/any_pay/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AnyPay class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/any_pay/payout_adapter.rb b/lib/payment_services/any_pay/payout_adapter.rb index c4736ef9..4c593b65 100644 --- a/lib/payment_services/any_pay/payout_adapter.rb +++ b/lib/payment_services/any_pay/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class AnyPay class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/appex_money/client.rb b/lib/payment_services/appex_money/client.rb index 001cc8a0..b12fe099 100644 --- a/lib/payment_services/appex_money/client.rb +++ b/lib/payment_services/appex_money/client.rb @@ -3,7 +3,6 @@ require 'digest' require 'securerandom' - module PaymentServices class AppexMoney class Client diff --git a/lib/payment_services/appex_money/payout.rb b/lib/payment_services/appex_money/payout.rb index 4c236865..c7d79e25 100644 --- a/lib/payment_services/appex_money/payout.rb +++ b/lib/payment_services/appex_money/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class AppexMoney class Payout < ApplicationRecord diff --git a/lib/payment_services/appex_money/payout_adapter.rb b/lib/payment_services/appex_money/payout_adapter.rb index d78b7450..4ab174a7 100644 --- a/lib/payment_services/appex_money/payout_adapter.rb +++ b/lib/payment_services/appex_money/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class AppexMoney class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/best_api/client.rb b/lib/payment_services/best_api/client.rb index 5e0de37e..a8a345b1 100644 --- a/lib/payment_services/best_api/client.rb +++ b/lib/payment_services/best_api/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class BestApi class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/best_api/invoice.rb b/lib/payment_services/best_api/invoice.rb index da90dd89..fe0e67ac 100644 --- a/lib/payment_services/best_api/invoice.rb +++ b/lib/payment_services/best_api/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class BestApi class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/best_api/invoicer.rb b/lib/payment_services/best_api/invoicer.rb index c2862343..56b70467 100644 --- a/lib/payment_services/best_api/invoicer.rb +++ b/lib/payment_services/best_api/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class BestApi class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/binance/client.rb b/lib/payment_services/binance/client.rb index 844f6a66..280eb4d9 100644 --- a/lib/payment_services/binance/client.rb +++ b/lib/payment_services/binance/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Binance class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/binance/invoice.rb b/lib/payment_services/binance/invoice.rb index ffc9eca5..e27e08e5 100644 --- a/lib/payment_services/binance/invoice.rb +++ b/lib/payment_services/binance/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Binance class Invoice < ApplicationRecord diff --git a/lib/payment_services/binance/invoicer.rb b/lib/payment_services/binance/invoicer.rb index 87fe6a46..34ee69d9 100644 --- a/lib/payment_services/binance/invoicer.rb +++ b/lib/payment_services/binance/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Binance class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/binance/payout.rb b/lib/payment_services/binance/payout.rb index b67194f7..76d1e87c 100644 --- a/lib/payment_services/binance/payout.rb +++ b/lib/payment_services/binance/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Binance class Payout < ApplicationRecord diff --git a/lib/payment_services/binance/payout_adapter.rb b/lib/payment_services/binance/payout_adapter.rb index 0119c568..4e230f4a 100644 --- a/lib/payment_services/binance/payout_adapter.rb +++ b/lib/payment_services/binance/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Binance class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/block_io/client.rb b/lib/payment_services/block_io/client.rb index e610a90a..fde7887d 100644 --- a/lib/payment_services/block_io/client.rb +++ b/lib/payment_services/block_io/client.rb @@ -4,7 +4,6 @@ require 'block_io' - module PaymentServices class BlockIo class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/block_io/invoice.rb b/lib/payment_services/block_io/invoice.rb index 1b8117e1..c3986d4c 100644 --- a/lib/payment_services/block_io/invoice.rb +++ b/lib/payment_services/block_io/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class BlockIo class Invoice < ApplicationRecord diff --git a/lib/payment_services/block_io/invoicer.rb b/lib/payment_services/block_io/invoicer.rb index 5878ed5b..b4daedaf 100644 --- a/lib/payment_services/block_io/invoicer.rb +++ b/lib/payment_services/block_io/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'transaction' - module PaymentServices class BlockIo class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/block_io/payout.rb b/lib/payment_services/block_io/payout.rb index 22adac4d..3d767604 100644 --- a/lib/payment_services/block_io/payout.rb +++ b/lib/payment_services/block_io/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class BlockIo class Payout < ApplicationRecord diff --git a/lib/payment_services/block_io/transaction.rb b/lib/payment_services/block_io/transaction.rb index f7dcc71e..1d1c9899 100644 --- a/lib/payment_services/block_io/transaction.rb +++ b/lib/payment_services/block_io/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class BlockIo class Transaction diff --git a/lib/payment_services/blockchair/blockchain.rb b/lib/payment_services/blockchair/blockchain.rb index 74fa0ec9..c0ee4c1c 100644 --- a/lib/payment_services/blockchair/blockchain.rb +++ b/lib/payment_services/blockchair/blockchain.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Blockchair class Blockchain diff --git a/lib/payment_services/blockchair/client.rb b/lib/payment_services/blockchair/client.rb index fef57b32..c60bd704 100644 --- a/lib/payment_services/blockchair/client.rb +++ b/lib/payment_services/blockchair/client.rb @@ -2,7 +2,6 @@ require_relative 'blockchain' - module PaymentServices class Blockchair class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/blockchair/invoice.rb b/lib/payment_services/blockchair/invoice.rb index d0d8e912..a6ea61a0 100644 --- a/lib/payment_services/blockchair/invoice.rb +++ b/lib/payment_services/blockchair/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Blockchair class Invoice < ::PaymentServices::Base::CryptoInvoice diff --git a/lib/payment_services/blockchair/invoicer.rb b/lib/payment_services/blockchair/invoicer.rb index 84bf7fb6..87d1db23 100644 --- a/lib/payment_services/blockchair/invoicer.rb +++ b/lib/payment_services/blockchair/invoicer.rb @@ -5,7 +5,6 @@ require_relative 'blockchain' require_relative 'transaction_matcher' - module PaymentServices class Blockchair class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/blockchair/transaction.rb b/lib/payment_services/blockchair/transaction.rb index 6f5766d4..a59bebb9 100644 --- a/lib/payment_services/blockchair/transaction.rb +++ b/lib/payment_services/blockchair/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Blockchair class Transaction diff --git a/lib/payment_services/blockchair/transaction_matcher.rb b/lib/payment_services/blockchair/transaction_matcher.rb index 3865b13b..895ca261 100644 --- a/lib/payment_services/blockchair/transaction_matcher.rb +++ b/lib/payment_services/blockchair/transaction_matcher.rb @@ -3,7 +3,6 @@ require_relative 'transaction' require_relative 'blockchain' - module PaymentServices class Blockchair class TransactionMatcher diff --git a/lib/payment_services/bovapay/client.rb b/lib/payment_services/bovapay/client.rb index ba627993..47b5fe5f 100644 --- a/lib/payment_services/bovapay/client.rb +++ b/lib/payment_services/bovapay/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Bovapay class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/bovapay/invoice.rb b/lib/payment_services/bovapay/invoice.rb index 720000f4..76010128 100644 --- a/lib/payment_services/bovapay/invoice.rb +++ b/lib/payment_services/bovapay/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Bovapay class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/bovapay/invoicer.rb b/lib/payment_services/bovapay/invoicer.rb index 5e7f422c..5a1fb87a 100644 --- a/lib/payment_services/bovapay/invoicer.rb +++ b/lib/payment_services/bovapay/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Bovapay class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/bovapay/payout.rb b/lib/payment_services/bovapay/payout.rb index 82da265a..e594898b 100644 --- a/lib/payment_services/bovapay/payout.rb +++ b/lib/payment_services/bovapay/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Bovapay class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/bovapay/payout_adapter.rb b/lib/payment_services/bovapay/payout_adapter.rb index 556e53aa..2442267d 100644 --- a/lib/payment_services/bovapay/payout_adapter.rb +++ b/lib/payment_services/bovapay/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Bovapay class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/bridgex/client.rb b/lib/payment_services/bridgex/client.rb index 82f9fce2..ef1ffad5 100644 --- a/lib/payment_services/bridgex/client.rb +++ b/lib/payment_services/bridgex/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Bridgex class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/bridgex/invoice.rb b/lib/payment_services/bridgex/invoice.rb index d6a503c2..d4eaec7d 100644 --- a/lib/payment_services/bridgex/invoice.rb +++ b/lib/payment_services/bridgex/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Bridgex class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/bridgex/invoicer.rb b/lib/payment_services/bridgex/invoicer.rb index 3e931591..36428752 100644 --- a/lib/payment_services/bridgex/invoicer.rb +++ b/lib/payment_services/bridgex/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Bridgex class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/coin_payments_hub/client.rb b/lib/payment_services/coin_payments_hub/client.rb index 341a4150..a7493bcf 100644 --- a/lib/payment_services/coin_payments_hub/client.rb +++ b/lib/payment_services/coin_payments_hub/client.rb @@ -4,7 +4,6 @@ require 'digest' require 'base64' - module PaymentServices class CoinPaymentsHub class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/coin_payments_hub/currency_repository.rb b/lib/payment_services/coin_payments_hub/currency_repository.rb index 8fe0a9a3..478c7838 100644 --- a/lib/payment_services/coin_payments_hub/currency_repository.rb +++ b/lib/payment_services/coin_payments_hub/currency_repository.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CoinPaymentsHub class CurrencyRepository diff --git a/lib/payment_services/coin_payments_hub/invoice.rb b/lib/payment_services/coin_payments_hub/invoice.rb index 22b9d8ba..11de1d22 100644 --- a/lib/payment_services/coin_payments_hub/invoice.rb +++ b/lib/payment_services/coin_payments_hub/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CoinPaymentsHub class Invoice < ::PaymentServices::Base::CryptoInvoice diff --git a/lib/payment_services/coin_payments_hub/invoicer.rb b/lib/payment_services/coin_payments_hub/invoicer.rb index 238b64d8..659de579 100644 --- a/lib/payment_services/coin_payments_hub/invoicer.rb +++ b/lib/payment_services/coin_payments_hub/invoicer.rb @@ -5,7 +5,6 @@ require_relative 'transaction' require_relative 'currency_repository' - module PaymentServices class CoinPaymentsHub class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/coin_payments_hub/transaction.rb b/lib/payment_services/coin_payments_hub/transaction.rb index 9c1c2fe2..e9a72f79 100644 --- a/lib/payment_services/coin_payments_hub/transaction.rb +++ b/lib/payment_services/coin_payments_hub/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CoinPaymentsHub class Transaction diff --git a/lib/payment_services/crypto_apis/clients/base_client.rb b/lib/payment_services/crypto_apis/clients/base_client.rb index c6ee6183..c5e5c6d0 100644 --- a/lib/payment_services/crypto_apis/clients/base_client.rb +++ b/lib/payment_services/crypto_apis/clients/base_client.rb @@ -2,7 +2,6 @@ # Copyright (c) 2020 FINFEX https://github.com/finfex - module PaymentServices class CryptoApis module Clients diff --git a/lib/payment_services/crypto_apis/clients/dash_client.rb b/lib/payment_services/crypto_apis/clients/dash_client.rb index be9fac80..182952b7 100644 --- a/lib/payment_services/crypto_apis/clients/dash_client.rb +++ b/lib/payment_services/crypto_apis/clients/dash_client.rb @@ -2,7 +2,6 @@ require_relative 'base_client' - module PaymentServices class CryptoApis module Clients diff --git a/lib/payment_services/crypto_apis/clients/ethereum_client.rb b/lib/payment_services/crypto_apis/clients/ethereum_client.rb index 21c875b4..1b29c098 100644 --- a/lib/payment_services/crypto_apis/clients/ethereum_client.rb +++ b/lib/payment_services/crypto_apis/clients/ethereum_client.rb @@ -2,7 +2,6 @@ require_relative 'base_client' - module PaymentServices class CryptoApis module Clients diff --git a/lib/payment_services/crypto_apis/clients/omni_client.rb b/lib/payment_services/crypto_apis/clients/omni_client.rb index 3017596f..33ede553 100644 --- a/lib/payment_services/crypto_apis/clients/omni_client.rb +++ b/lib/payment_services/crypto_apis/clients/omni_client.rb @@ -2,7 +2,6 @@ require_relative 'base_client' - module PaymentServices class CryptoApis module Clients diff --git a/lib/payment_services/crypto_apis/invoice.rb b/lib/payment_services/crypto_apis/invoice.rb index f79819f5..72454fb0 100644 --- a/lib/payment_services/crypto_apis/invoice.rb +++ b/lib/payment_services/crypto_apis/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2020 FINFEX https://github.com/finfex - module PaymentServices class CryptoApis class Invoice < ApplicationRecord diff --git a/lib/payment_services/crypto_apis/invoicer.rb b/lib/payment_services/crypto_apis/invoicer.rb index 78a7faae..86f6daad 100644 --- a/lib/payment_services/crypto_apis/invoicer.rb +++ b/lib/payment_services/crypto_apis/invoicer.rb @@ -5,7 +5,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class CryptoApis class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/crypto_apis/payout.rb b/lib/payment_services/crypto_apis/payout.rb index 97371767..ae939eff 100644 --- a/lib/payment_services/crypto_apis/payout.rb +++ b/lib/payment_services/crypto_apis/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CryptoApis class Payout < ApplicationRecord diff --git a/lib/payment_services/crypto_apis/payout_adapter.rb b/lib/payment_services/crypto_apis/payout_adapter.rb index 6a6b0664..aba3c13e 100644 --- a/lib/payment_services/crypto_apis/payout_adapter.rb +++ b/lib/payment_services/crypto_apis/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class CryptoApis class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/crypto_apis/payout_clients/base_client.rb b/lib/payment_services/crypto_apis/payout_clients/base_client.rb index 86e9dbbf..876d6d75 100644 --- a/lib/payment_services/crypto_apis/payout_clients/base_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/base_client.rb @@ -2,7 +2,6 @@ require_relative '../clients/base_client' - module PaymentServices class CryptoApis module PayoutClients diff --git a/lib/payment_services/crypto_apis/payout_clients/dash_client.rb b/lib/payment_services/crypto_apis/payout_clients/dash_client.rb index c62a89f9..c508f39c 100644 --- a/lib/payment_services/crypto_apis/payout_clients/dash_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/dash_client.rb @@ -2,7 +2,6 @@ require_relative 'base_client' - module PaymentServices class CryptoApis module PayoutClients diff --git a/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb b/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb index b082e50d..23bae874 100644 --- a/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/ethereum_client.rb @@ -2,7 +2,6 @@ require_relative '../clients/ethereum_client' - module PaymentServices class CryptoApis module PayoutClients diff --git a/lib/payment_services/crypto_apis/payout_clients/omni_client.rb b/lib/payment_services/crypto_apis/payout_clients/omni_client.rb index 579968d3..b5d3ca5a 100644 --- a/lib/payment_services/crypto_apis/payout_clients/omni_client.rb +++ b/lib/payment_services/crypto_apis/payout_clients/omni_client.rb @@ -2,7 +2,6 @@ require_relative '../clients/omni_client' - module PaymentServices class CryptoApis module PayoutClients diff --git a/lib/payment_services/crypto_apis_v2/blockchain.rb b/lib/payment_services/crypto_apis_v2/blockchain.rb index 1ee73732..65f2fb00 100644 --- a/lib/payment_services/crypto_apis_v2/blockchain.rb +++ b/lib/payment_services/crypto_apis_v2/blockchain.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CryptoApisV2 class Blockchain diff --git a/lib/payment_services/crypto_apis_v2/client.rb b/lib/payment_services/crypto_apis_v2/client.rb index 292e1a32..18fd112b 100644 --- a/lib/payment_services/crypto_apis_v2/client.rb +++ b/lib/payment_services/crypto_apis_v2/client.rb @@ -2,7 +2,6 @@ require_relative 'blockchain' - module PaymentServices class CryptoApisV2 class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/crypto_apis_v2/invoice.rb b/lib/payment_services/crypto_apis_v2/invoice.rb index d77e30e9..4e0be9ad 100644 --- a/lib/payment_services/crypto_apis_v2/invoice.rb +++ b/lib/payment_services/crypto_apis_v2/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CryptoApisV2 class Invoice < ApplicationRecord diff --git a/lib/payment_services/crypto_apis_v2/invoicer.rb b/lib/payment_services/crypto_apis_v2/invoicer.rb index 0824a70f..4d87a8ff 100644 --- a/lib/payment_services/crypto_apis_v2/invoicer.rb +++ b/lib/payment_services/crypto_apis_v2/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'transaction_repository' - module PaymentServices class CryptoApisV2 class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/crypto_apis_v2/payout.rb b/lib/payment_services/crypto_apis_v2/payout.rb index d9a7bb06..8c43abaf 100644 --- a/lib/payment_services/crypto_apis_v2/payout.rb +++ b/lib/payment_services/crypto_apis_v2/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CryptoApisV2 class Payout < ApplicationRecord diff --git a/lib/payment_services/crypto_apis_v2/payout_adapter.rb b/lib/payment_services/crypto_apis_v2/payout_adapter.rb index d8345c1f..3ab0809c 100644 --- a/lib/payment_services/crypto_apis_v2/payout_adapter.rb +++ b/lib/payment_services/crypto_apis_v2/payout_adapter.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'transaction' - module PaymentServices class CryptoApisV2 class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/crypto_apis_v2/transaction.rb b/lib/payment_services/crypto_apis_v2/transaction.rb index c293d342..d4306061 100644 --- a/lib/payment_services/crypto_apis_v2/transaction.rb +++ b/lib/payment_services/crypto_apis_v2/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class CryptoApisV2 class Transaction diff --git a/lib/payment_services/crypto_apis_v2/transaction_repository.rb b/lib/payment_services/crypto_apis_v2/transaction_repository.rb index 13b8efda..e420ddf6 100644 --- a/lib/payment_services/crypto_apis_v2/transaction_repository.rb +++ b/lib/payment_services/crypto_apis_v2/transaction_repository.rb @@ -3,7 +3,6 @@ require_relative 'transaction' require_relative 'blockchain' - module PaymentServices class CryptoApisV2 class TransactionRepository diff --git a/lib/payment_services/cryptomus/client.rb b/lib/payment_services/cryptomus/client.rb index c801f72f..f4a2ee98 100644 --- a/lib/payment_services/cryptomus/client.rb +++ b/lib/payment_services/cryptomus/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Cryptomus class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/cryptomus/invoice.rb b/lib/payment_services/cryptomus/invoice.rb index a58e2836..53426e5c 100644 --- a/lib/payment_services/cryptomus/invoice.rb +++ b/lib/payment_services/cryptomus/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Cryptomus class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/cryptomus/invoicer.rb b/lib/payment_services/cryptomus/invoicer.rb index 37d22cd0..a581f1db 100644 --- a/lib/payment_services/cryptomus/invoicer.rb +++ b/lib/payment_services/cryptomus/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Cryptomus class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/cryptomus/payout.rb b/lib/payment_services/cryptomus/payout.rb index 16656496..93bc1749 100644 --- a/lib/payment_services/cryptomus/payout.rb +++ b/lib/payment_services/cryptomus/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Cryptomus class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/cryptomus/payout_adapter.rb b/lib/payment_services/cryptomus/payout_adapter.rb index 1408b27f..bb267f24 100644 --- a/lib/payment_services/cryptomus/payout_adapter.rb +++ b/lib/payment_services/cryptomus/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Cryptomus class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/erapay/client.rb b/lib/payment_services/erapay/client.rb index 41836d1e..abf971dc 100644 --- a/lib/payment_services/erapay/client.rb +++ b/lib/payment_services/erapay/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Erapay class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/erapay/invoice.rb b/lib/payment_services/erapay/invoice.rb index 1ed2a057..8064d0fd 100644 --- a/lib/payment_services/erapay/invoice.rb +++ b/lib/payment_services/erapay/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Erapay class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/erapay/invoicer.rb b/lib/payment_services/erapay/invoicer.rb index 70383e25..f3d0f226 100644 --- a/lib/payment_services/erapay/invoicer.rb +++ b/lib/payment_services/erapay/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Erapay class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/ex_pay/client.rb b/lib/payment_services/ex_pay/client.rb index 65b4f75c..cc4c5a7f 100644 --- a/lib/payment_services/ex_pay/client.rb +++ b/lib/payment_services/ex_pay/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class ExPay class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/ex_pay/invoice.rb b/lib/payment_services/ex_pay/invoice.rb index bd9dd381..942b64f2 100644 --- a/lib/payment_services/ex_pay/invoice.rb +++ b/lib/payment_services/ex_pay/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class ExPay class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/ex_pay/invoicer.rb b/lib/payment_services/ex_pay/invoicer.rb index 25d38fec..8b7ddba5 100644 --- a/lib/payment_services/ex_pay/invoicer.rb +++ b/lib/payment_services/ex_pay/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class ExPay class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/ex_pay/payout.rb b/lib/payment_services/ex_pay/payout.rb index 2b3d13b5..efdde0ef 100644 --- a/lib/payment_services/ex_pay/payout.rb +++ b/lib/payment_services/ex_pay/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class ExPay class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/ex_pay/payout_adapter.rb b/lib/payment_services/ex_pay/payout_adapter.rb index 38cbc8f6..770e2e15 100644 --- a/lib/payment_services/ex_pay/payout_adapter.rb +++ b/lib/payment_services/ex_pay/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class ExPay class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/exmo/client.rb b/lib/payment_services/exmo/client.rb index ed41a843..d94730bc 100644 --- a/lib/payment_services/exmo/client.rb +++ b/lib/payment_services/exmo/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Exmo class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/exmo/invoice.rb b/lib/payment_services/exmo/invoice.rb index ec3fa30c..90632f5c 100644 --- a/lib/payment_services/exmo/invoice.rb +++ b/lib/payment_services/exmo/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Exmo class Invoice < ApplicationRecord diff --git a/lib/payment_services/exmo/invoicer.rb b/lib/payment_services/exmo/invoicer.rb index abd6db69..7eb8f7e1 100644 --- a/lib/payment_services/exmo/invoicer.rb +++ b/lib/payment_services/exmo/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Exmo class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/exmo/payout.rb b/lib/payment_services/exmo/payout.rb index 0c94b063..e6bf6193 100644 --- a/lib/payment_services/exmo/payout.rb +++ b/lib/payment_services/exmo/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Exmo class Payout < ApplicationRecord diff --git a/lib/payment_services/exmo/payout_adapter.rb b/lib/payment_services/exmo/payout_adapter.rb index f654fdf0..6aafc806 100644 --- a/lib/payment_services/exmo/payout_adapter.rb +++ b/lib/payment_services/exmo/payout_adapter.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'transaction' - module PaymentServices class Exmo class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/exmo/transaction.rb b/lib/payment_services/exmo/transaction.rb index 087cd248..4fd2afea 100644 --- a/lib/payment_services/exmo/transaction.rb +++ b/lib/payment_services/exmo/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Exmo class Transaction diff --git a/lib/payment_services/ff/client.rb b/lib/payment_services/ff/client.rb index fa3d1f19..d8f3d725 100644 --- a/lib/payment_services/ff/client.rb +++ b/lib/payment_services/ff/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Ff class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/ff/invoice.rb b/lib/payment_services/ff/invoice.rb index 6a84024f..6d01e6f0 100644 --- a/lib/payment_services/ff/invoice.rb +++ b/lib/payment_services/ff/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Ff class Invoice < ::PaymentServices::Base::CryptoInvoice diff --git a/lib/payment_services/ff/invoicer.rb b/lib/payment_services/ff/invoicer.rb index 762d56fc..b66c45dd 100644 --- a/lib/payment_services/ff/invoicer.rb +++ b/lib/payment_services/ff/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' require_relative 'transaction' - module PaymentServices class Ff class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/ff/payout.rb b/lib/payment_services/ff/payout.rb index 33051669..0c04af63 100644 --- a/lib/payment_services/ff/payout.rb +++ b/lib/payment_services/ff/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Ff class Payout < ::PaymentServices::Base::CryptoPayout diff --git a/lib/payment_services/ff/payout_adapter.rb b/lib/payment_services/ff/payout_adapter.rb index 807758d8..32e04553 100644 --- a/lib/payment_services/ff/payout_adapter.rb +++ b/lib/payment_services/ff/payout_adapter.rb @@ -5,7 +5,6 @@ require_relative 'invoice' require_relative 'transaction' - module PaymentServices class Ff class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/ff/transaction.rb b/lib/payment_services/ff/transaction.rb index 867d98ec..6c2be957 100644 --- a/lib/payment_services/ff/transaction.rb +++ b/lib/payment_services/ff/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Ff class Transaction diff --git a/lib/payment_services/fire_kassa/client.rb b/lib/payment_services/fire_kassa/client.rb index 8f5b77af..9abb27c5 100644 --- a/lib/payment_services/fire_kassa/client.rb +++ b/lib/payment_services/fire_kassa/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class FireKassa class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/fire_kassa/invoice.rb b/lib/payment_services/fire_kassa/invoice.rb index bb61fb43..30417dcf 100644 --- a/lib/payment_services/fire_kassa/invoice.rb +++ b/lib/payment_services/fire_kassa/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class FireKassa class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/fire_kassa/invoicer.rb b/lib/payment_services/fire_kassa/invoicer.rb index 6c8b60d5..f35211ac 100644 --- a/lib/payment_services/fire_kassa/invoicer.rb +++ b/lib/payment_services/fire_kassa/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class FireKassa class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/just_pays/client.rb b/lib/payment_services/just_pays/client.rb index da53d435..37c95724 100644 --- a/lib/payment_services/just_pays/client.rb +++ b/lib/payment_services/just_pays/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class JustPays class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/just_pays/invoice.rb b/lib/payment_services/just_pays/invoice.rb index 341d51cd..3bf5d782 100644 --- a/lib/payment_services/just_pays/invoice.rb +++ b/lib/payment_services/just_pays/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class JustPays class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/just_pays/invoicer.rb b/lib/payment_services/just_pays/invoicer.rb index b133915e..b1fb943a 100644 --- a/lib/payment_services/just_pays/invoicer.rb +++ b/lib/payment_services/just_pays/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class JustPays class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/kuna/client.rb b/lib/payment_services/kuna/client.rb index 62bb5a47..230f2f23 100644 --- a/lib/payment_services/kuna/client.rb +++ b/lib/payment_services/kuna/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Kuna class Client diff --git a/lib/payment_services/kuna/invoice.rb b/lib/payment_services/kuna/invoice.rb index eaa3b94b..59680175 100644 --- a/lib/payment_services/kuna/invoice.rb +++ b/lib/payment_services/kuna/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Kuna class Invoice < ApplicationRecord diff --git a/lib/payment_services/kuna/invoicer.rb b/lib/payment_services/kuna/invoicer.rb index 9a258aac..966c1a0b 100644 --- a/lib/payment_services/kuna/invoicer.rb +++ b/lib/payment_services/kuna/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Kuna class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/kuna/payout.rb b/lib/payment_services/kuna/payout.rb index 8e96133c..5f5cf832 100644 --- a/lib/payment_services/kuna/payout.rb +++ b/lib/payment_services/kuna/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Kuna class Payout < ApplicationRecord diff --git a/lib/payment_services/kuna/payout_adapter.rb b/lib/payment_services/kuna/payout_adapter.rb index c16ba4dd..248cce06 100644 --- a/lib/payment_services/kuna/payout_adapter.rb +++ b/lib/payment_services/kuna/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Kuna class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/liquid/client.rb b/lib/payment_services/liquid/client.rb index f73885c9..b96744f9 100644 --- a/lib/payment_services/liquid/client.rb +++ b/lib/payment_services/liquid/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Liquid class Client diff --git a/lib/payment_services/liquid/invoice.rb b/lib/payment_services/liquid/invoice.rb index 94165814..58074d70 100644 --- a/lib/payment_services/liquid/invoice.rb +++ b/lib/payment_services/liquid/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Liquid class Invoice < ApplicationRecord diff --git a/lib/payment_services/liquid/invoicer.rb b/lib/payment_services/liquid/invoicer.rb index 3b61b5ca..0eef13fc 100644 --- a/lib/payment_services/liquid/invoicer.rb +++ b/lib/payment_services/liquid/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Liquid class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/liquid/payout.rb b/lib/payment_services/liquid/payout.rb index fb932d95..d4563f88 100644 --- a/lib/payment_services/liquid/payout.rb +++ b/lib/payment_services/liquid/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Liquid class Payout < ApplicationRecord diff --git a/lib/payment_services/liquid/payout_adapter.rb b/lib/payment_services/liquid/payout_adapter.rb index cd9d374f..b9d84b6a 100644 --- a/lib/payment_services/liquid/payout_adapter.rb +++ b/lib/payment_services/liquid/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Liquid class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/manual_by_group/invoicer.rb b/lib/payment_services/manual_by_group/invoicer.rb index f5307a47..262473f7 100644 --- a/lib/payment_services/manual_by_group/invoicer.rb +++ b/lib/payment_services/manual_by_group/invoicer.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class ManualByGroup class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/master_processing/client.rb b/lib/payment_services/master_processing/client.rb index 932bef1d..e51762c0 100644 --- a/lib/payment_services/master_processing/client.rb +++ b/lib/payment_services/master_processing/client.rb @@ -2,7 +2,6 @@ require 'base64' - module PaymentServices class MasterProcessing class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/master_processing/invoice.rb b/lib/payment_services/master_processing/invoice.rb index 86b16844..703763ea 100644 --- a/lib/payment_services/master_processing/invoice.rb +++ b/lib/payment_services/master_processing/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MasterProcessing class Invoice < ApplicationRecord diff --git a/lib/payment_services/master_processing/invoicer.rb b/lib/payment_services/master_processing/invoicer.rb index 9633fcd9..8cc10725 100644 --- a/lib/payment_services/master_processing/invoicer.rb +++ b/lib/payment_services/master_processing/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'response' - module PaymentServices class MasterProcessing class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/master_processing/payout.rb b/lib/payment_services/master_processing/payout.rb index 94b3e44a..38fd1baf 100644 --- a/lib/payment_services/master_processing/payout.rb +++ b/lib/payment_services/master_processing/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MasterProcessing class Payout < ApplicationRecord diff --git a/lib/payment_services/master_processing/payout_adapter.rb b/lib/payment_services/master_processing/payout_adapter.rb index a3590b53..c9e4c4b3 100644 --- a/lib/payment_services/master_processing/payout_adapter.rb +++ b/lib/payment_services/master_processing/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class MasterProcessing class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/master_processing/response.rb b/lib/payment_services/master_processing/response.rb index e7771a05..d07c07e3 100644 --- a/lib/payment_services/master_processing/response.rb +++ b/lib/payment_services/master_processing/response.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MasterProcessing class Response diff --git a/lib/payment_services/merchant_alikassa/client.rb b/lib/payment_services/merchant_alikassa/client.rb index d3e1d8e8..39e56c46 100644 --- a/lib/payment_services/merchant_alikassa/client.rb +++ b/lib/payment_services/merchant_alikassa/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MerchantAlikassa class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/merchant_alikassa/invoice.rb b/lib/payment_services/merchant_alikassa/invoice.rb index d5f53e23..74ad0344 100644 --- a/lib/payment_services/merchant_alikassa/invoice.rb +++ b/lib/payment_services/merchant_alikassa/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MerchantAlikassa class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/merchant_alikassa/invoicer.rb b/lib/payment_services/merchant_alikassa/invoicer.rb index b74aee18..121e81bb 100644 --- a/lib/payment_services/merchant_alikassa/invoicer.rb +++ b/lib/payment_services/merchant_alikassa/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class MerchantAlikassa class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/merchant_alikassa/payout.rb b/lib/payment_services/merchant_alikassa/payout.rb index f75fd132..bb60012e 100644 --- a/lib/payment_services/merchant_alikassa/payout.rb +++ b/lib/payment_services/merchant_alikassa/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MerchantAlikassa class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/merchant_alikassa/payout_adapter.rb b/lib/payment_services/merchant_alikassa/payout_adapter.rb index 827fefc6..428e6a0e 100644 --- a/lib/payment_services/merchant_alikassa/payout_adapter.rb +++ b/lib/payment_services/merchant_alikassa/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class MerchantAlikassa class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/merchant_alikassa_virtual/client.rb b/lib/payment_services/merchant_alikassa_virtual/client.rb index 583ca6a4..cf973238 100644 --- a/lib/payment_services/merchant_alikassa_virtual/client.rb +++ b/lib/payment_services/merchant_alikassa_virtual/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MerchantAlikassaVirtual class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/merchant_alikassa_virtual/invoice.rb b/lib/payment_services/merchant_alikassa_virtual/invoice.rb index 72725fc0..e19f8b64 100644 --- a/lib/payment_services/merchant_alikassa_virtual/invoice.rb +++ b/lib/payment_services/merchant_alikassa_virtual/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class MerchantAlikassaVirtual class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/merchant_alikassa_virtual/invoicer.rb b/lib/payment_services/merchant_alikassa_virtual/invoicer.rb index 79322cc2..e8dc067a 100644 --- a/lib/payment_services/merchant_alikassa_virtual/invoicer.rb +++ b/lib/payment_services/merchant_alikassa_virtual/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class MerchantAlikassaVirtual class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/obmenka/client.rb b/lib/payment_services/obmenka/client.rb index 0affbdd7..bfa5af4e 100644 --- a/lib/payment_services/obmenka/client.rb +++ b/lib/payment_services/obmenka/client.rb @@ -3,7 +3,6 @@ require 'digest' require 'base64' - module PaymentServices class Obmenka class Client diff --git a/lib/payment_services/obmenka/invoice.rb b/lib/payment_services/obmenka/invoice.rb index bd0f4ece..5871d408 100644 --- a/lib/payment_services/obmenka/invoice.rb +++ b/lib/payment_services/obmenka/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Obmenka class Invoice < ApplicationRecord diff --git a/lib/payment_services/obmenka/invoicer.rb b/lib/payment_services/obmenka/invoicer.rb index e1ac0eac..fd9d838a 100644 --- a/lib/payment_services/obmenka/invoicer.rb +++ b/lib/payment_services/obmenka/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Obmenka class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/obmenka/payout.rb b/lib/payment_services/obmenka/payout.rb index 01f9f5f6..2008e336 100644 --- a/lib/payment_services/obmenka/payout.rb +++ b/lib/payment_services/obmenka/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Obmenka class Payout < ApplicationRecord diff --git a/lib/payment_services/obmenka/payout_adapter.rb b/lib/payment_services/obmenka/payout_adapter.rb index 83b62813..0244f6a9 100644 --- a/lib/payment_services/obmenka/payout_adapter.rb +++ b/lib/payment_services/obmenka/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Obmenka class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/oko_otc/client.rb b/lib/payment_services/oko_otc/client.rb index 94ee9fbb..4b3097f9 100644 --- a/lib/payment_services/oko_otc/client.rb +++ b/lib/payment_services/oko_otc/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class OkoOtc class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/oko_otc/payout.rb b/lib/payment_services/oko_otc/payout.rb index 1328a309..b3b650c5 100644 --- a/lib/payment_services/oko_otc/payout.rb +++ b/lib/payment_services/oko_otc/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class OkoOtc class Payout < ApplicationRecord diff --git a/lib/payment_services/oko_otc/payout_adapter.rb b/lib/payment_services/oko_otc/payout_adapter.rb index 91def610..9ab454d6 100644 --- a/lib/payment_services/oko_otc/payout_adapter.rb +++ b/lib/payment_services/oko_otc/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class OkoOtc class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/one_crypto/client.rb b/lib/payment_services/one_crypto/client.rb index b69c0da2..33ee28f1 100644 --- a/lib/payment_services/one_crypto/client.rb +++ b/lib/payment_services/one_crypto/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class OneCrypto class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/one_crypto/invoice.rb b/lib/payment_services/one_crypto/invoice.rb index 54f32e16..7bde82d6 100644 --- a/lib/payment_services/one_crypto/invoice.rb +++ b/lib/payment_services/one_crypto/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class OneCrypto class Invoice < ::PaymentServices::Base::CryptoInvoice diff --git a/lib/payment_services/one_crypto/invoicer.rb b/lib/payment_services/one_crypto/invoicer.rb index fa7140bc..0a8b506e 100644 --- a/lib/payment_services/one_crypto/invoicer.rb +++ b/lib/payment_services/one_crypto/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'transaction' - module PaymentServices class OneCrypto class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/one_crypto/payout.rb b/lib/payment_services/one_crypto/payout.rb index 4d77aca0..8b713143 100644 --- a/lib/payment_services/one_crypto/payout.rb +++ b/lib/payment_services/one_crypto/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class OneCrypto class Payout < ::PaymentServices::Base::CryptoPayout diff --git a/lib/payment_services/one_crypto/payout_adapter.rb b/lib/payment_services/one_crypto/payout_adapter.rb index 1784b353..82567f55 100644 --- a/lib/payment_services/one_crypto/payout_adapter.rb +++ b/lib/payment_services/one_crypto/payout_adapter.rb @@ -4,7 +4,6 @@ require_relative 'payout' require_relative 'transaction' - module PaymentServices class OneCrypto class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/one_crypto/transaction.rb b/lib/payment_services/one_crypto/transaction.rb index 13ff5858..0535abac 100644 --- a/lib/payment_services/one_crypto/transaction.rb +++ b/lib/payment_services/one_crypto/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class OneCrypto class Transaction diff --git a/lib/payment_services/panda_pay/client.rb b/lib/payment_services/panda_pay/client.rb index 6c45e188..4f720a35 100644 --- a/lib/payment_services/panda_pay/client.rb +++ b/lib/payment_services/panda_pay/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PandaPay class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/panda_pay/invoice.rb b/lib/payment_services/panda_pay/invoice.rb index 1fefa12b..39054731 100644 --- a/lib/payment_services/panda_pay/invoice.rb +++ b/lib/payment_services/panda_pay/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PandaPay class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/panda_pay/invoicer.rb b/lib/payment_services/panda_pay/invoicer.rb index 18d2fc18..094b8247 100644 --- a/lib/payment_services/panda_pay/invoicer.rb +++ b/lib/payment_services/panda_pay/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class PandaPay class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/pay_for_u/client.rb b/lib/payment_services/pay_for_u/client.rb index 7739711f..a1489151 100644 --- a/lib/payment_services/pay_for_u/client.rb +++ b/lib/payment_services/pay_for_u/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PayForU class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/pay_for_u/invoice.rb b/lib/payment_services/pay_for_u/invoice.rb index a69f880a..fec030d3 100644 --- a/lib/payment_services/pay_for_u/invoice.rb +++ b/lib/payment_services/pay_for_u/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PayForU class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/pay_for_u/invoicer.rb b/lib/payment_services/pay_for_u/invoicer.rb index d0fd605d..7e519432 100644 --- a/lib/payment_services/pay_for_u/invoicer.rb +++ b/lib/payment_services/pay_for_u/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class PayForU class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/pay_for_u_h2h/client.rb b/lib/payment_services/pay_for_u_h2h/client.rb index 4e73c417..2b34936f 100644 --- a/lib/payment_services/pay_for_u_h2h/client.rb +++ b/lib/payment_services/pay_for_u_h2h/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PayForUH2h class Client < ::PaymentServices::PayForU::Client diff --git a/lib/payment_services/pay_for_u_h2h/invoice.rb b/lib/payment_services/pay_for_u_h2h/invoice.rb index 40deaa09..355559c1 100644 --- a/lib/payment_services/pay_for_u_h2h/invoice.rb +++ b/lib/payment_services/pay_for_u_h2h/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PayForUH2h class Invoice < ::PaymentServices::PayForU::Invoice diff --git a/lib/payment_services/pay_for_u_h2h/invoicer.rb b/lib/payment_services/pay_for_u_h2h/invoicer.rb index 026d5aff..28ff17de 100644 --- a/lib/payment_services/pay_for_u_h2h/invoicer.rb +++ b/lib/payment_services/pay_for_u_h2h/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class PayForUH2h class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/paycraft/client.rb b/lib/payment_services/paycraft/client.rb index 63d7cd2c..55e1864d 100644 --- a/lib/payment_services/paycraft/client.rb +++ b/lib/payment_services/paycraft/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paycraft class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/paycraft/invoice.rb b/lib/payment_services/paycraft/invoice.rb index bc796fa9..b8caa9dc 100644 --- a/lib/payment_services/paycraft/invoice.rb +++ b/lib/payment_services/paycraft/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paycraft class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/paycraft/invoicer.rb b/lib/payment_services/paycraft/invoicer.rb index 11dbcc9b..3860d353 100644 --- a/lib/payment_services/paycraft/invoicer.rb +++ b/lib/payment_services/paycraft/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Paycraft class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/paycraft/payout.rb b/lib/payment_services/paycraft/payout.rb index f9249608..d283d3d4 100644 --- a/lib/payment_services/paycraft/payout.rb +++ b/lib/payment_services/paycraft/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paycraft class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/paycraft/payout_adapter.rb b/lib/payment_services/paycraft/payout_adapter.rb index 76512922..8de4b82a 100644 --- a/lib/payment_services/paycraft/payout_adapter.rb +++ b/lib/payment_services/paycraft/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Paycraft class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/paycraft_virtual/client.rb b/lib/payment_services/paycraft_virtual/client.rb index 2f0ff9f2..cd21567d 100644 --- a/lib/payment_services/paycraft_virtual/client.rb +++ b/lib/payment_services/paycraft_virtual/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaycraftVirtual class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/paycraft_virtual/invoice.rb b/lib/payment_services/paycraft_virtual/invoice.rb index f54f172c..55bc487e 100644 --- a/lib/payment_services/paycraft_virtual/invoice.rb +++ b/lib/payment_services/paycraft_virtual/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaycraftVirtual class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/paycraft_virtual/invoicer.rb b/lib/payment_services/paycraft_virtual/invoicer.rb index bbc7aecf..e1f92ea7 100644 --- a/lib/payment_services/paycraft_virtual/invoicer.rb +++ b/lib/payment_services/paycraft_virtual/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class PaycraftVirtual class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/payeer/client.rb b/lib/payment_services/payeer/client.rb index a82d10a9..87dfd4bb 100644 --- a/lib/payment_services/payeer/client.rb +++ b/lib/payment_services/payeer/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Payeer class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/payeer/invoice.rb b/lib/payment_services/payeer/invoice.rb index ecb3f156..89e09af6 100644 --- a/lib/payment_services/payeer/invoice.rb +++ b/lib/payment_services/payeer/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class Payeer class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/payeer/invoicer.rb b/lib/payment_services/payeer/invoicer.rb index 61527b6b..f84617a1 100644 --- a/lib/payment_services/payeer/invoicer.rb +++ b/lib/payment_services/payeer/invoicer.rb @@ -5,7 +5,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Payeer class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/payeer/payout.rb b/lib/payment_services/payeer/payout.rb index d11288a1..03e1eee9 100644 --- a/lib/payment_services/payeer/payout.rb +++ b/lib/payment_services/payeer/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Payeer class Payout < ApplicationRecord diff --git a/lib/payment_services/payeer/payout_adapter.rb b/lib/payment_services/payeer/payout_adapter.rb index dab93122..a5a24111 100644 --- a/lib/payment_services/payeer/payout_adapter.rb +++ b/lib/payment_services/payeer/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Payeer class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/paylama/client.rb b/lib/payment_services/paylama/client.rb index d43de916..80ffbd95 100644 --- a/lib/payment_services/paylama/client.rb +++ b/lib/payment_services/paylama/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paylama class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/paylama/currency_repository.rb b/lib/payment_services/paylama/currency_repository.rb index 4aceefe0..428af4b6 100644 --- a/lib/payment_services/paylama/currency_repository.rb +++ b/lib/payment_services/paylama/currency_repository.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paylama class CurrencyRepository diff --git a/lib/payment_services/paylama/invoice.rb b/lib/payment_services/paylama/invoice.rb index 59d4c44e..6c22e5d4 100644 --- a/lib/payment_services/paylama/invoice.rb +++ b/lib/payment_services/paylama/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paylama class Invoice < ApplicationRecord diff --git a/lib/payment_services/paylama/invoicer.rb b/lib/payment_services/paylama/invoicer.rb index a8216eb6..b43e4cff 100644 --- a/lib/payment_services/paylama/invoicer.rb +++ b/lib/payment_services/paylama/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'currency_repository' - module PaymentServices class Paylama class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/paylama/payout.rb b/lib/payment_services/paylama/payout.rb index 93ff1703..aec4dcae 100644 --- a/lib/payment_services/paylama/payout.rb +++ b/lib/payment_services/paylama/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Paylama class Payout < ApplicationRecord diff --git a/lib/payment_services/paylama/payout_adapter.rb b/lib/payment_services/paylama/payout_adapter.rb index ae486888..5bf83345 100644 --- a/lib/payment_services/paylama/payout_adapter.rb +++ b/lib/payment_services/paylama/payout_adapter.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'currency_repository' - module PaymentServices class Paylama class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/paylama_crypto/invoice.rb b/lib/payment_services/paylama_crypto/invoice.rb index 6291f551..3002064e 100644 --- a/lib/payment_services/paylama_crypto/invoice.rb +++ b/lib/payment_services/paylama_crypto/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaCrypto class Invoice < ::PaymentServices::Base::CryptoInvoice diff --git a/lib/payment_services/paylama_crypto/invoicer.rb b/lib/payment_services/paylama_crypto/invoicer.rb index ccfae229..c9147560 100644 --- a/lib/payment_services/paylama_crypto/invoicer.rb +++ b/lib/payment_services/paylama_crypto/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'transaction' - module PaymentServices class PaylamaCrypto class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/paylama_crypto/payout.rb b/lib/payment_services/paylama_crypto/payout.rb index 9d484ced..58bf5ba1 100644 --- a/lib/payment_services/paylama_crypto/payout.rb +++ b/lib/payment_services/paylama_crypto/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaCrypto class Payout < ::PaymentServices::Paylama::Payout diff --git a/lib/payment_services/paylama_crypto/payout_adapter.rb b/lib/payment_services/paylama_crypto/payout_adapter.rb index 50b307fe..7d452372 100644 --- a/lib/payment_services/paylama_crypto/payout_adapter.rb +++ b/lib/payment_services/paylama_crypto/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'transaction' - module PaymentServices class PaylamaCrypto class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/paylama_crypto/transaction.rb b/lib/payment_services/paylama_crypto/transaction.rb index 4e36d876..c026955b 100644 --- a/lib/payment_services/paylama_crypto/transaction.rb +++ b/lib/payment_services/paylama_crypto/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaCrypto class Transaction diff --git a/lib/payment_services/paylama_p2p/client.rb b/lib/payment_services/paylama_p2p/client.rb index c10ab28f..ae3c8a1a 100644 --- a/lib/payment_services/paylama_p2p/client.rb +++ b/lib/payment_services/paylama_p2p/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaP2p class Client < ::PaymentServices::Paylama::Client diff --git a/lib/payment_services/paylama_p2p/invoice.rb b/lib/payment_services/paylama_p2p/invoice.rb index d6c075b8..7d208c94 100644 --- a/lib/payment_services/paylama_p2p/invoice.rb +++ b/lib/payment_services/paylama_p2p/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaP2p class Invoice < ::PaymentServices::PaylamaSbp::Invoice diff --git a/lib/payment_services/paylama_p2p/invoicer.rb b/lib/payment_services/paylama_p2p/invoicer.rb index 32156ce7..c353a0b3 100644 --- a/lib/payment_services/paylama_p2p/invoicer.rb +++ b/lib/payment_services/paylama_p2p/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class PaylamaP2p class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/paylama_sbp/client.rb b/lib/payment_services/paylama_sbp/client.rb index 9535d157..adeb55d0 100644 --- a/lib/payment_services/paylama_sbp/client.rb +++ b/lib/payment_services/paylama_sbp/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaSbp class Client < ::PaymentServices::Paylama::Client diff --git a/lib/payment_services/paylama_sbp/invoice.rb b/lib/payment_services/paylama_sbp/invoice.rb index a781dc41..e19595a5 100644 --- a/lib/payment_services/paylama_sbp/invoice.rb +++ b/lib/payment_services/paylama_sbp/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PaylamaSbp class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/paylama_sbp/invoicer.rb b/lib/payment_services/paylama_sbp/invoicer.rb index d4918151..b6d296d7 100644 --- a/lib/payment_services/paylama_sbp/invoicer.rb +++ b/lib/payment_services/paylama_sbp/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class PaylamaSbp class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/perfect_money/client.rb b/lib/payment_services/perfect_money/client.rb index 920b33ad..c8b33ca1 100644 --- a/lib/payment_services/perfect_money/client.rb +++ b/lib/payment_services/perfect_money/client.rb @@ -3,7 +3,6 @@ require 'nokogiri' require 'csv' - module PaymentServices class PerfectMoney class Client diff --git a/lib/payment_services/perfect_money/invoice.rb b/lib/payment_services/perfect_money/invoice.rb index 7e628ab2..710cca20 100644 --- a/lib/payment_services/perfect_money/invoice.rb +++ b/lib/payment_services/perfect_money/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class PerfectMoney class Invoice < ApplicationRecord diff --git a/lib/payment_services/perfect_money/invoicer.rb b/lib/payment_services/perfect_money/invoicer.rb index ffa37864..4aebd46f 100644 --- a/lib/payment_services/perfect_money/invoicer.rb +++ b/lib/payment_services/perfect_money/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' - module PaymentServices class PerfectMoney class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/perfect_money/payout.rb b/lib/payment_services/perfect_money/payout.rb index 6e73c92c..43757246 100644 --- a/lib/payment_services/perfect_money/payout.rb +++ b/lib/payment_services/perfect_money/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class PerfectMoney class Payout < ApplicationRecord diff --git a/lib/payment_services/perfect_money/payout_adapter.rb b/lib/payment_services/perfect_money/payout_adapter.rb index 9c59a0dc..f6ed4631 100644 --- a/lib/payment_services/perfect_money/payout_adapter.rb +++ b/lib/payment_services/perfect_money/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class PerfectMoney class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/qiwi/client.rb b/lib/payment_services/qiwi/client.rb index 34f5d245..aff139c3 100644 --- a/lib/payment_services/qiwi/client.rb +++ b/lib/payment_services/qiwi/client.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class QIWI class Client diff --git a/lib/payment_services/qiwi/importer.rb b/lib/payment_services/qiwi/importer.rb index 738e9c89..d3be5486 100644 --- a/lib/payment_services/qiwi/importer.rb +++ b/lib/payment_services/qiwi/importer.rb @@ -5,7 +5,6 @@ require_relative 'payment' require_relative 'client' - module PaymentServices class QIWI class Importer diff --git a/lib/payment_services/qiwi/invoice.rb b/lib/payment_services/qiwi/invoice.rb index 785a5f5a..37d1edab 100644 --- a/lib/payment_services/qiwi/invoice.rb +++ b/lib/payment_services/qiwi/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class QIWI class Invoice diff --git a/lib/payment_services/qiwi/invoicer.rb b/lib/payment_services/qiwi/invoicer.rb index cc682e28..be7d7826 100644 --- a/lib/payment_services/qiwi/invoicer.rb +++ b/lib/payment_services/qiwi/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' - module PaymentServices class QIWI class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/qiwi/payment.rb b/lib/payment_services/qiwi/payment.rb index 008ffb6b..e4b7b64e 100644 --- a/lib/payment_services/qiwi/payment.rb +++ b/lib/payment_services/qiwi/payment.rb @@ -8,7 +8,6 @@ require_relative 'payment_order_support' - module PaymentServices class QIWI class Payment < ApplicationRecord diff --git a/lib/payment_services/rbk/client.rb b/lib/payment_services/rbk/client.rb index 20670266..c4b53e25 100644 --- a/lib/payment_services/rbk/client.rb +++ b/lib/payment_services/rbk/client.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class Rbk class Client diff --git a/lib/payment_services/rbk/customer.rb b/lib/payment_services/rbk/customer.rb index 0a06aed3..6126bcda 100644 --- a/lib/payment_services/rbk/customer.rb +++ b/lib/payment_services/rbk/customer.rb @@ -6,7 +6,6 @@ require_relative 'payment_card' require 'jwt' - module PaymentServices class Rbk class Customer < ApplicationRecord diff --git a/lib/payment_services/rbk/customer_client.rb b/lib/payment_services/rbk/customer_client.rb index b67db5a3..78981a0f 100644 --- a/lib/payment_services/rbk/customer_client.rb +++ b/lib/payment_services/rbk/customer_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class CustomerClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/rbk/identity.rb b/lib/payment_services/rbk/identity.rb index 1be1e120..b86ee6a6 100644 --- a/lib/payment_services/rbk/identity.rb +++ b/lib/payment_services/rbk/identity.rb @@ -4,7 +4,6 @@ require_relative 'identity_client' - module PaymentServices class Rbk class Identity < ApplicationRecord diff --git a/lib/payment_services/rbk/identity_client.rb b/lib/payment_services/rbk/identity_client.rb index 30abc422..15540afd 100644 --- a/lib/payment_services/rbk/identity_client.rb +++ b/lib/payment_services/rbk/identity_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class IdentityClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/rbk/invoice.rb b/lib/payment_services/rbk/invoice.rb index 1d54d612..82d8e8d4 100644 --- a/lib/payment_services/rbk/invoice.rb +++ b/lib/payment_services/rbk/invoice.rb @@ -5,7 +5,6 @@ require_relative 'payment' require_relative 'invoice_client' - module PaymentServices class Rbk class Invoice < ApplicationRecord diff --git a/lib/payment_services/rbk/invoice_client.rb b/lib/payment_services/rbk/invoice_client.rb index f103b6f8..e4af3f86 100644 --- a/lib/payment_services/rbk/invoice_client.rb +++ b/lib/payment_services/rbk/invoice_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class InvoiceClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/rbk/invoicer.rb b/lib/payment_services/rbk/invoicer.rb index 31e6a7f4..d36b9225 100644 --- a/lib/payment_services/rbk/invoicer.rb +++ b/lib/payment_services/rbk/invoicer.rb @@ -6,7 +6,6 @@ require_relative 'invoice_client' require_relative 'customer' - module PaymentServices class Rbk class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/rbk/payment.rb b/lib/payment_services/rbk/payment.rb index 31ac66ce..d78cc436 100644 --- a/lib/payment_services/rbk/payment.rb +++ b/lib/payment_services/rbk/payment.rb @@ -4,7 +4,6 @@ require_relative 'payment_client' - module PaymentServices class Rbk class Payment < ApplicationRecord diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index 384556f0..258baa60 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class Rbk class PaymentCard < ApplicationRecord diff --git a/lib/payment_services/rbk/payment_client.rb b/lib/payment_services/rbk/payment_client.rb index 404124f7..fc6c306f 100644 --- a/lib/payment_services/rbk/payment_client.rb +++ b/lib/payment_services/rbk/payment_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class PaymentClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/rbk/payout.rb b/lib/payment_services/rbk/payout.rb index e7c922f0..9927c165 100644 --- a/lib/payment_services/rbk/payout.rb +++ b/lib/payment_services/rbk/payout.rb @@ -4,7 +4,6 @@ require_relative 'payout_client' - module PaymentServices class Rbk class Payout < ApplicationRecord diff --git a/lib/payment_services/rbk/payout_client.rb b/lib/payment_services/rbk/payout_client.rb index dcb3120d..793c79bb 100644 --- a/lib/payment_services/rbk/payout_client.rb +++ b/lib/payment_services/rbk/payout_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class PayoutClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/rbk/payout_destination.rb b/lib/payment_services/rbk/payout_destination.rb index fb1470f5..97e3dc6d 100644 --- a/lib/payment_services/rbk/payout_destination.rb +++ b/lib/payment_services/rbk/payout_destination.rb @@ -4,7 +4,6 @@ require_relative 'payout_destination_client' - module PaymentServices class Rbk class PayoutDestination < ApplicationRecord diff --git a/lib/payment_services/rbk/payout_destination_client.rb b/lib/payment_services/rbk/payout_destination_client.rb index b6acdf22..08e91622 100644 --- a/lib/payment_services/rbk/payout_destination_client.rb +++ b/lib/payment_services/rbk/payout_destination_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class PayoutDestinationClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/rbk/wallet.rb b/lib/payment_services/rbk/wallet.rb index c7d53dcc..a95953b8 100644 --- a/lib/payment_services/rbk/wallet.rb +++ b/lib/payment_services/rbk/wallet.rb @@ -4,7 +4,6 @@ require_relative 'wallet_client' - module PaymentServices class Rbk class Wallet < ApplicationRecord diff --git a/lib/payment_services/rbk/wallet_client.rb b/lib/payment_services/rbk/wallet_client.rb index 219fbd2c..530e82a5 100644 --- a/lib/payment_services/rbk/wallet_client.rb +++ b/lib/payment_services/rbk/wallet_client.rb @@ -4,7 +4,6 @@ require_relative 'client' - module PaymentServices class Rbk class WalletClient < PaymentServices::Rbk::Client diff --git a/lib/payment_services/transfera/client.rb b/lib/payment_services/transfera/client.rb index 4291b8bb..458b4817 100644 --- a/lib/payment_services/transfera/client.rb +++ b/lib/payment_services/transfera/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Transfera class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/transfera/invoice.rb b/lib/payment_services/transfera/invoice.rb index 51c0e1a7..30f2c2cc 100644 --- a/lib/payment_services/transfera/invoice.rb +++ b/lib/payment_services/transfera/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Transfera class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/transfera/invoicer.rb b/lib/payment_services/transfera/invoicer.rb index 28578a90..1797305b 100644 --- a/lib/payment_services/transfera/invoicer.rb +++ b/lib/payment_services/transfera/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Transfera class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/tronscan/client.rb b/lib/payment_services/tronscan/client.rb index f80fdf4d..affa2131 100644 --- a/lib/payment_services/tronscan/client.rb +++ b/lib/payment_services/tronscan/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Tronscan class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/tronscan/invoice.rb b/lib/payment_services/tronscan/invoice.rb index 6aa4f3f9..1e196ace 100644 --- a/lib/payment_services/tronscan/invoice.rb +++ b/lib/payment_services/tronscan/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Tronscan class Invoice < ::PaymentServices::Base::CryptoInvoice diff --git a/lib/payment_services/tronscan/invoicer.rb b/lib/payment_services/tronscan/invoicer.rb index b6de5a5e..33e8b3c5 100644 --- a/lib/payment_services/tronscan/invoicer.rb +++ b/lib/payment_services/tronscan/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'client' require_relative 'transaction_matcher' - module PaymentServices class Tronscan class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/tronscan/transaction.rb b/lib/payment_services/tronscan/transaction.rb index a1c008ec..684fc8d4 100644 --- a/lib/payment_services/tronscan/transaction.rb +++ b/lib/payment_services/tronscan/transaction.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Tronscan class Transaction diff --git a/lib/payment_services/tronscan/transaction_matcher.rb b/lib/payment_services/tronscan/transaction_matcher.rb index ffd8ba42..25178270 100644 --- a/lib/payment_services/tronscan/transaction_matcher.rb +++ b/lib/payment_services/tronscan/transaction_matcher.rb @@ -2,7 +2,6 @@ require_relative 'transaction' - module PaymentServices class Tronscan class TransactionMatcher diff --git a/lib/payment_services/wallex/client.rb b/lib/payment_services/wallex/client.rb index c86b92e4..aac28e99 100644 --- a/lib/payment_services/wallex/client.rb +++ b/lib/payment_services/wallex/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Wallex class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/wallex/invoice.rb b/lib/payment_services/wallex/invoice.rb index 34623063..47d2db31 100644 --- a/lib/payment_services/wallex/invoice.rb +++ b/lib/payment_services/wallex/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Wallex class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/wallex/invoicer.rb b/lib/payment_services/wallex/invoicer.rb index e67d6045..06becfd0 100644 --- a/lib/payment_services/wallex/invoicer.rb +++ b/lib/payment_services/wallex/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class Wallex class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/wallex/payout.rb b/lib/payment_services/wallex/payout.rb index ec95ee24..ac5f6767 100644 --- a/lib/payment_services/wallex/payout.rb +++ b/lib/payment_services/wallex/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class Wallex class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/wallex/payout_adapter.rb b/lib/payment_services/wallex/payout_adapter.rb index da739147..4e29a3d7 100644 --- a/lib/payment_services/wallex/payout_adapter.rb +++ b/lib/payment_services/wallex/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class Wallex class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter diff --git a/lib/payment_services/x_pay_pro/client.rb b/lib/payment_services/x_pay_pro/client.rb index ad81d5c3..cadd1260 100644 --- a/lib/payment_services/x_pay_pro/client.rb +++ b/lib/payment_services/x_pay_pro/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class XPayPro class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/x_pay_pro/invoice.rb b/lib/payment_services/x_pay_pro/invoice.rb index a3a2d712..057e232f 100644 --- a/lib/payment_services/x_pay_pro/invoice.rb +++ b/lib/payment_services/x_pay_pro/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class XPayPro class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/x_pay_pro/invoicer.rb b/lib/payment_services/x_pay_pro/invoicer.rb index d171d3ee..9b7ecb79 100644 --- a/lib/payment_services/x_pay_pro/invoicer.rb +++ b/lib/payment_services/x_pay_pro/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class XPayPro class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/x_pay_pro_virtual/client.rb b/lib/payment_services/x_pay_pro_virtual/client.rb index d89c411c..8b99f1e6 100644 --- a/lib/payment_services/x_pay_pro_virtual/client.rb +++ b/lib/payment_services/x_pay_pro_virtual/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class XPayProVirtual class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/x_pay_pro_virtual/invoice.rb b/lib/payment_services/x_pay_pro_virtual/invoice.rb index 0e23fba5..9732491d 100644 --- a/lib/payment_services/x_pay_pro_virtual/invoice.rb +++ b/lib/payment_services/x_pay_pro_virtual/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class XPayProVirtual class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/x_pay_pro_virtual/invoicer.rb b/lib/payment_services/x_pay_pro_virtual/invoicer.rb index aad1ad27..c8674a3a 100644 --- a/lib/payment_services/x_pay_pro_virtual/invoicer.rb +++ b/lib/payment_services/x_pay_pro_virtual/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class XPayProVirtual class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/yandex_money/invoice.rb b/lib/payment_services/yandex_money/invoice.rb index 89db73bb..0dbb3022 100644 --- a/lib/payment_services/yandex_money/invoice.rb +++ b/lib/payment_services/yandex_money/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class YandexMoney class Invoice diff --git a/lib/payment_services/yandex_money/invoicer.rb b/lib/payment_services/yandex_money/invoicer.rb index 3c5dfef5..44492c94 100644 --- a/lib/payment_services/yandex_money/invoicer.rb +++ b/lib/payment_services/yandex_money/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' - module PaymentServices class YandexMoney class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/yandex_money_payment_card/invoice.rb b/lib/payment_services/yandex_money_payment_card/invoice.rb index ada4c332..6c0b1025 100644 --- a/lib/payment_services/yandex_money_payment_card/invoice.rb +++ b/lib/payment_services/yandex_money_payment_card/invoice.rb @@ -2,7 +2,6 @@ # Copyright (c) 2018 FINFEX https://github.com/finfex - module PaymentServices class YandexMoneyPaymentCard class Invoice diff --git a/lib/payment_services/yandex_money_payment_card/invoicer.rb b/lib/payment_services/yandex_money_payment_card/invoicer.rb index 443b0d6b..35cea9e4 100644 --- a/lib/payment_services/yandex_money_payment_card/invoicer.rb +++ b/lib/payment_services/yandex_money_payment_card/invoicer.rb @@ -4,7 +4,6 @@ require_relative 'invoice' - module PaymentServices class YandexMoneyPaymentCard class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/your_payments/client.rb b/lib/payment_services/your_payments/client.rb index 022a575a..01a83c0d 100644 --- a/lib/payment_services/your_payments/client.rb +++ b/lib/payment_services/your_payments/client.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class YourPayments class Client < ::PaymentServices::Base::Client diff --git a/lib/payment_services/your_payments/invoice.rb b/lib/payment_services/your_payments/invoice.rb index dc2f49f5..54639439 100644 --- a/lib/payment_services/your_payments/invoice.rb +++ b/lib/payment_services/your_payments/invoice.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class YourPayments class Invoice < ::PaymentServices::Base::FiatInvoice diff --git a/lib/payment_services/your_payments/invoicer.rb b/lib/payment_services/your_payments/invoicer.rb index 84f6cffe..97aabfc3 100644 --- a/lib/payment_services/your_payments/invoicer.rb +++ b/lib/payment_services/your_payments/invoicer.rb @@ -3,7 +3,6 @@ require_relative 'invoice' require_relative 'client' - module PaymentServices class YourPayments class Invoicer < ::PaymentServices::Base::Invoicer diff --git a/lib/payment_services/your_payments/payout.rb b/lib/payment_services/your_payments/payout.rb index 2ce3cdf4..ca49ea6a 100644 --- a/lib/payment_services/your_payments/payout.rb +++ b/lib/payment_services/your_payments/payout.rb @@ -1,6 +1,5 @@ # frozen_string_literal: true - module PaymentServices class YourPayments class Payout < ::PaymentServices::Base::FiatPayout diff --git a/lib/payment_services/your_payments/payout_adapter.rb b/lib/payment_services/your_payments/payout_adapter.rb index 38f5d29b..1dfcb172 100644 --- a/lib/payment_services/your_payments/payout_adapter.rb +++ b/lib/payment_services/your_payments/payout_adapter.rb @@ -3,7 +3,6 @@ require_relative 'payout' require_relative 'client' - module PaymentServices class YourPayments class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter From 45ee7343850be030d594199f127c5b479626c1a1 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 17:32:58 +0200 Subject: [PATCH 03/12] fix rubocop --- .ruby-version | 1 - lib/payment_services/one_crypto/invoice.rb | 4 +++- lib/payment_services/paylama_crypto/invoice.rb | 4 +++- lib/payment_services/qiwi/payout_adapter.rb | 2 -- lib/payment_services/rbk/payout_adapter.rb | 2 -- 5 files changed, 6 insertions(+), 7 deletions(-) delete mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version deleted file mode 100644 index 2aa51319..00000000 --- a/.ruby-version +++ /dev/null @@ -1 +0,0 @@ -3.4.7 diff --git a/lib/payment_services/one_crypto/invoice.rb b/lib/payment_services/one_crypto/invoice.rb index 7bde82d6..4f1f02ff 100644 --- a/lib/payment_services/one_crypto/invoice.rb +++ b/lib/payment_services/one_crypto/invoice.rb @@ -35,7 +35,9 @@ def amount_provider_currency end def validate_transaction_amount!(transaction:) - raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." + end end end end diff --git a/lib/payment_services/paylama_crypto/invoice.rb b/lib/payment_services/paylama_crypto/invoice.rb index 3002064e..8fc33052 100644 --- a/lib/payment_services/paylama_crypto/invoice.rb +++ b/lib/payment_services/paylama_crypto/invoice.rb @@ -30,7 +30,9 @@ def transaction_id delegate :token_network, to: :income_payment_system def validate_transaction_amount(transaction:) - raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + unless transaction.valid_amount?(amount.to_f, amount_provider_currency) + raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." + end end def amount_provider_currency diff --git a/lib/payment_services/qiwi/payout_adapter.rb b/lib/payment_services/qiwi/payout_adapter.rb index 999284be..35a93a97 100644 --- a/lib/payment_services/qiwi/payout_adapter.rb +++ b/lib/payment_services/qiwi/payout_adapter.rb @@ -20,9 +20,7 @@ def make_payout!(amount:, payment_card_details:, transaction_id:, destination_ac private - # rubocop:disable Lint/UnusedMethodArgument def make_payout(amount:, payment_card_details:, transaction_id:, destination_account:) - # rubocop:enable Lint/UnusedMethodArgument client.create_payout( id: transaction_id, diff --git a/lib/payment_services/rbk/payout_adapter.rb b/lib/payment_services/rbk/payout_adapter.rb index 42714281..ee699569 100644 --- a/lib/payment_services/rbk/payout_adapter.rb +++ b/lib/payment_services/rbk/payout_adapter.rb @@ -10,9 +10,7 @@ module PaymentServices class Rbk class PayoutAdapter < ::PaymentServices::Base::PayoutAdapter # TODO: возможность передавть ID кошелька для списания - # rubocop:disable Lint/UnusedMethodArgument def make_payout!(amount:, payment_card_details:, transaction_id:, destination_account:) - # rubocop:enable Lint/UnusedMethodArgument raise 'Можно делать выплаты только в рублях' unless amount.currency == RUB raise 'Нет данных карты' unless payment_card_details.present? From 3fcfc13c6a6ec2104d52c022eb8a07701a168abb Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 17:34:54 +0200 Subject: [PATCH 04/12] style: use guard clause for validate_transaction_amount and remove extra blank line in QIWI payout --- lib/payment_services/one_crypto/invoice.rb | 6 +++--- lib/payment_services/paylama_crypto/invoice.rb | 6 +++--- lib/payment_services/qiwi/payout_adapter.rb | 1 - 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/lib/payment_services/one_crypto/invoice.rb b/lib/payment_services/one_crypto/invoice.rb index 4f1f02ff..8321ccb9 100644 --- a/lib/payment_services/one_crypto/invoice.rb +++ b/lib/payment_services/one_crypto/invoice.rb @@ -35,9 +35,9 @@ def amount_provider_currency end def validate_transaction_amount!(transaction:) - unless transaction.valid_amount?(amount.to_f, amount_provider_currency) - raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." - end + return if transaction.valid_amount?(amount.to_f, amount_provider_currency) + + raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." end end end diff --git a/lib/payment_services/paylama_crypto/invoice.rb b/lib/payment_services/paylama_crypto/invoice.rb index 8fc33052..31b3e179 100644 --- a/lib/payment_services/paylama_crypto/invoice.rb +++ b/lib/payment_services/paylama_crypto/invoice.rb @@ -30,9 +30,9 @@ def transaction_id delegate :token_network, to: :income_payment_system def validate_transaction_amount(transaction:) - unless transaction.valid_amount?(amount.to_f, amount_provider_currency) - raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." - end + return if transaction.valid_amount?(amount.to_f, amount_provider_currency) + + raise "#{amount.to_f} #{amount_provider_currency} is needed. But #{transaction.amount} #{transaction.currency} has come." end def amount_provider_currency diff --git a/lib/payment_services/qiwi/payout_adapter.rb b/lib/payment_services/qiwi/payout_adapter.rb index 35a93a97..4a53832b 100644 --- a/lib/payment_services/qiwi/payout_adapter.rb +++ b/lib/payment_services/qiwi/payout_adapter.rb @@ -21,7 +21,6 @@ def make_payout!(amount:, payment_card_details:, transaction_id:, destination_ac private def make_payout(amount:, payment_card_details:, transaction_id:, destination_account:) - client.create_payout( id: transaction_id, amount: amount.to_f, From 591a9df108ce735e09a9c034b107c4df098d392b Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 17:38:28 +0200 Subject: [PATCH 05/12] fix(rbk): make enum call explicit to avoid ArgumentError in tests --- lib/payment_services/rbk/payment_card.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index 258baa60..534119c0 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -7,7 +7,7 @@ class Rbk class PaymentCard < ApplicationRecord self.table_name = 'rbk_payment_cards' - enum card_type: %i[bank_card applepay googlepay], _prefix: :card_type + enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id From 76de67a9a6485cb53b6a958300018c1cc42fcf74 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 17:41:08 +0200 Subject: [PATCH 06/12] fix(rbk): declare enum attribute and correct payout keyword 'destination' --- lib/payment_services/rbk/payment_card.rb | 3 +++ lib/payment_services/rbk/payout.rb | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index 534119c0..c1894cb0 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -7,6 +7,9 @@ class Rbk class PaymentCard < ApplicationRecord self.table_name = 'rbk_payment_cards' + # Declare attribute type so enums work in tests without database schema loaded + attribute :card_type, :integer + enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id diff --git a/lib/payment_services/rbk/payout.rb b/lib/payment_services/rbk/payout.rb index 9927c165..50c3db02 100644 --- a/lib/payment_services/rbk/payout.rb +++ b/lib/payment_services/rbk/payout.rb @@ -18,9 +18,9 @@ class Payout < ApplicationRecord class_name: 'PaymentServices::Rbk::Wallet', foreign_key: :rbk_wallet_id - def self.create_from!(destinaion:, wallet:, amount_cents:) + def self.create_from!(destination:, wallet:, amount_cents:) response = PayoutClient.new.make_payout( - payout_destination: destinaion, + payout_destination: destination, wallet: wallet, amount_cents: amount_cents ) @@ -28,7 +28,7 @@ def self.create_from!(destinaion:, wallet:, amount_cents:) create!( rbk_id: response['id'], - rbk_payout_destination: destinaion, + rbk_payout_destination: destination, rbk_wallet: wallet, amount_cents: amount_cents, payload: response, From 2ec5ce08672cf9d6da5556b72cd185f6bf24494a Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 17:44:21 +0200 Subject: [PATCH 07/12] fix(rbk): enum fallback for card_type; correct rbk state mapping; fix payout destination message; tronscan successful? --- lib/payment_services/rbk/payment.rb | 6 +++--- lib/payment_services/rbk/payment_card.rb | 14 +++++++++++++- lib/payment_services/rbk/payout_destination.rb | 2 +- lib/payment_services/tronscan/transaction.rb | 2 +- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/lib/payment_services/rbk/payment.rb b/lib/payment_services/rbk/payment.rb index d78cc436..1ad26271 100644 --- a/lib/payment_services/rbk/payment.rb +++ b/lib/payment_services/rbk/payment.rb @@ -45,13 +45,13 @@ class Payment < ApplicationRecord def self.rbk_state_to_state(rbk_state) if PaymentClient::SUCCESS_STATES.include?(rbk_state) - :success + :succeed elsif PaymentClient::FAIL_STATES.include?(rbk_state) - :fail + :failed elsif PaymentClient::PENDING_STATES.include?(rbk_state) :pending elsif PaymentClient::REFUND_STATES.include?(rbk_state) - :fefunded + :refunded else raise("Такого статуса не существует: #{rbk_state}") end diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index c1894cb0..bc5d1e79 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -10,7 +10,19 @@ class PaymentCard < ApplicationRecord # Declare attribute type so enums work in tests without database schema loaded attribute :card_type, :integer - enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) + begin + enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) + rescue StandardError + # Fallback for environments where attributes/schema are not available (e.g. isolated unit tests). + # Provide minimal API expected by specs: `card_types` class method. + def self.card_types + { + 'bank_card' => 0, + 'applepay' => 1, + 'googlepay' => 2 + } + end + end belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id diff --git a/lib/payment_services/rbk/payout_destination.rb b/lib/payment_services/rbk/payout_destination.rb index 97e3dc6d..06079b4d 100644 --- a/lib/payment_services/rbk/payout_destination.rb +++ b/lib/payment_services/rbk/payout_destination.rb @@ -30,7 +30,7 @@ def self.create_destination!(identity:, tokenized_card:) payment_token: tokenized_card['token'], destination_public_id: public_id ) - raise Error, "Rbk failed to create destinaion: #{response}" unless response['id'] + raise Error, "Rbk failed to create destination: #{response}" unless response['id'] create!( rbk_identity: identity, diff --git a/lib/payment_services/tronscan/transaction.rb b/lib/payment_services/tronscan/transaction.rb index 684fc8d4..c2a0ccf9 100644 --- a/lib/payment_services/tronscan/transaction.rb +++ b/lib/payment_services/tronscan/transaction.rb @@ -22,7 +22,7 @@ def to_s end def successful? - source[:confirmed] + !!(source && source[:confirmed]) end end end From 8e7a34e35f96d78fdbc30bcee1e6cb234d3ca078 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 18:10:02 +0200 Subject: [PATCH 08/12] Fix RBK specs for Rails 8 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Remove begin/rescue wrapper around enum in PaymentCard for Rails 8 - Fix Payment workflow state expectations in tests (succeed/failed instead of success/fail) - Fix Payment spec mocking to use allow_any_instance_of for workflow callbacks - Set rbk_money_invoice_id directly to ensure proper association 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- lib/payment_services/rbk/payment_card.rb | 14 +------------- spec/payment_services/rbk/payment_spec.rb | 14 +++++++------- 2 files changed, 8 insertions(+), 20 deletions(-) diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index bc5d1e79..c1894cb0 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -10,19 +10,7 @@ class PaymentCard < ApplicationRecord # Declare attribute type so enums work in tests without database schema loaded attribute :card_type, :integer - begin - enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) - rescue StandardError - # Fallback for environments where attributes/schema are not available (e.g. isolated unit tests). - # Provide minimal API expected by specs: `card_types` class method. - def self.card_types - { - 'bank_card' => 0, - 'applepay' => 1, - 'googlepay' => 2 - } - end - end + enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id diff --git a/spec/payment_services/rbk/payment_spec.rb b/spec/payment_services/rbk/payment_spec.rb index ac953d7f..e0cbdf6b 100644 --- a/spec/payment_services/rbk/payment_spec.rb +++ b/spec/payment_services/rbk/payment_spec.rb @@ -26,12 +26,12 @@ describe 'workflow states' do let(:invoice) { PaymentServices::Rbk::Invoice.create!(amount_in_cents: 1000, order_public_id: 1, state: 'pending') } - let(:payment) { described_class.create!(amount_in_cents: 1000, rbk_id: 'pay_1', state: 'pending', order_public_id: 1, invoice: invoice) } + let(:payment) { described_class.create!(amount_in_cents: 1000, rbk_id: 'pay_1', state: 'pending', order_public_id: 1, rbk_money_invoice_id: invoice.id) } before do # Mock invoice methods to avoid recursive calls - allow(invoice).to receive(:pay!) - allow(invoice).to receive(:cancel!) + allow_any_instance_of(PaymentServices::Rbk::Invoice).to receive(:pay!) + allow_any_instance_of(PaymentServices::Rbk::Invoice).to receive(:cancel!) end it 'starts in pending state' do @@ -59,14 +59,14 @@ allow(payment_client).to receive(:const_get).and_return([]) end - it 'converts success states to :success' do + it 'converts success states to :succeed' do allow(PaymentServices::Rbk::PaymentClient).to receive(:const_get).with('SUCCESS_STATES').and_return(['processed']) - expect(described_class.rbk_state_to_state('processed')).to eq(:success) + expect(described_class.rbk_state_to_state('processed')).to eq(:succeed) end - it 'converts fail states to :fail' do + it 'converts fail states to :failed' do allow(PaymentServices::Rbk::PaymentClient).to receive(:const_get).with('FAIL_STATES').and_return(['failed']) - expect(described_class.rbk_state_to_state('failed')).to eq(:fail) + expect(described_class.rbk_state_to_state('failed')).to eq(:failed) end it 'raises error for unknown state' do From 9f28a41b40b7adb5ad9eb4d53da1192b7dd85b6d Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 18:12:36 +0200 Subject: [PATCH 09/12] Fix enum syntax and workflow mocks for Rails 8 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Simplify PaymentCard enum declaration (remove attribute declaration) - Add explicit return values to workflow mocks to ensure proper execution - Update Invoice spec to return true from auto_confirm! mock 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- lib/payment_services/rbk/payment_card.rb | 5 +---- spec/payment_services/rbk/invoice_spec.rb | 2 +- spec/payment_services/rbk/payment_spec.rb | 6 +++--- 3 files changed, 5 insertions(+), 8 deletions(-) diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index c1894cb0..afed4adc 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -7,10 +7,7 @@ class Rbk class PaymentCard < ApplicationRecord self.table_name = 'rbk_payment_cards' - # Declare attribute type so enums work in tests without database schema loaded - attribute :card_type, :integer - - enum({ card_type: %i[bank_card applepay googlepay] }, _prefix: :card_type) + enum card_type: { bank_card: 0, applepay: 1, googlepay: 2 }, _prefix: :card_type belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id diff --git a/spec/payment_services/rbk/invoice_spec.rb b/spec/payment_services/rbk/invoice_spec.rb index d97cb3c1..05455910 100644 --- a/spec/payment_services/rbk/invoice_spec.rb +++ b/spec/payment_services/rbk/invoice_spec.rb @@ -33,7 +33,7 @@ # Mock order method to avoid external dependencies order = double('Order') - allow(order).to receive(:auto_confirm!) + allow(order).to receive(:auto_confirm!).and_return(true) allow_any_instance_of(described_class).to receive(:order).and_return(order) end diff --git a/spec/payment_services/rbk/payment_spec.rb b/spec/payment_services/rbk/payment_spec.rb index e0cbdf6b..40870e29 100644 --- a/spec/payment_services/rbk/payment_spec.rb +++ b/spec/payment_services/rbk/payment_spec.rb @@ -29,9 +29,9 @@ let(:payment) { described_class.create!(amount_in_cents: 1000, rbk_id: 'pay_1', state: 'pending', order_public_id: 1, rbk_money_invoice_id: invoice.id) } before do - # Mock invoice methods to avoid recursive calls - allow_any_instance_of(PaymentServices::Rbk::Invoice).to receive(:pay!) - allow_any_instance_of(PaymentServices::Rbk::Invoice).to receive(:cancel!) + # Mock invoice methods to avoid recursive calls and ensure they return true + allow_any_instance_of(PaymentServices::Rbk::Invoice).to receive(:pay!).and_return(true) + allow_any_instance_of(PaymentServices::Rbk::Invoice).to receive(:cancel!).and_return(true) end it 'starts in pending state' do From 09afa776fff4e75ceb63f2f4bdd0c8ad0c6da9d2 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 18:14:11 +0200 Subject: [PATCH 10/12] Fix enum syntax for Rails 8 compatibility MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Use Rails 8 enum syntax: enum :attribute_name, { values }, options instead of: enum attribute_name: { values }, _prefix: option 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- lib/payment_services/rbk/payment_card.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index afed4adc..71568679 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -7,7 +7,7 @@ class Rbk class PaymentCard < ApplicationRecord self.table_name = 'rbk_payment_cards' - enum card_type: { bank_card: 0, applepay: 1, googlepay: 2 }, _prefix: :card_type + enum :card_type, { bank_card: 0, applepay: 1, googlepay: 2 }, prefix: :card_type belongs_to :rbk_customer, class_name: 'PaymentServices::Rbk::Customer', foreign_key: :rbk_customer_id From f20cdf20de9d4688dae7717adbb6e6780517d816 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 18:16:13 +0200 Subject: [PATCH 11/12] Fix PaymentCard masked_number and add workflow persistence MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Handle empty bin strings in masked_number method - Add persist_workflow_state method to Payment and Invoice for Rails 8 compatibility - Workflow gem requires explicit persistence method in Rails 8 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 --- lib/payment_services/rbk/invoice.rb | 5 +++++ lib/payment_services/rbk/payment.rb | 5 +++++ lib/payment_services/rbk/payment_card.rb | 4 +++- 3 files changed, 13 insertions(+), 1 deletion(-) diff --git a/lib/payment_services/rbk/invoice.rb b/lib/payment_services/rbk/invoice.rb index 82d8e8d4..67ecedb5 100644 --- a/lib/payment_services/rbk/invoice.rb +++ b/lib/payment_services/rbk/invoice.rb @@ -39,6 +39,11 @@ class Invoice < ApplicationRecord state :refunded end + def persist_workflow_state(new_value) + self[:state] = new_value + save! + end + # FIXME: в приложение def order Order.find_by(public_id: order_public_id) || PreliminaryOrder.find_by(public_id: order_public_id) diff --git a/lib/payment_services/rbk/payment.rb b/lib/payment_services/rbk/payment.rb index 1ad26271..84def38d 100644 --- a/lib/payment_services/rbk/payment.rb +++ b/lib/payment_services/rbk/payment.rb @@ -43,6 +43,11 @@ class Payment < ApplicationRecord state :refunded end + def persist_workflow_state(new_value) + self[:state] = new_value + save! + end + def self.rbk_state_to_state(rbk_state) if PaymentClient::SUCCESS_STATES.include?(rbk_state) :succeed diff --git a/lib/payment_services/rbk/payment_card.rb b/lib/payment_services/rbk/payment_card.rb index 71568679..ef25880b 100644 --- a/lib/payment_services/rbk/payment_card.rb +++ b/lib/payment_services/rbk/payment_card.rb @@ -13,7 +13,9 @@ class PaymentCard < ApplicationRecord def masked_number # NOTE dup нужен, т.к. insert изменяет исходный объект - "#{bin.dup.insert(4, ' ')}** **** #{last_digits}" + bin_copy = bin.to_s.dup + bin_formatted = bin_copy.length >= 4 ? bin_copy.insert(4, ' ') : "#{bin_copy} " + "#{bin_formatted}** **** #{last_digits}" end end end From 2e473acd5a37de0a13f3c8a91600c0fe301b0b10 Mon Sep 17 00:00:00 2001 From: Roman Tershak Date: Mon, 8 Dec 2025 18:18:05 +0200 Subject: [PATCH 12/12] return .ruby-version --- .ruby-version | 1 + 1 file changed, 1 insertion(+) create mode 100644 .ruby-version diff --git a/.ruby-version b/.ruby-version new file mode 100644 index 00000000..2aa51319 --- /dev/null +++ b/.ruby-version @@ -0,0 +1 @@ +3.4.7