Last active
December 16, 2024 06:28
-
-
Save ryenski/0a9cee0509187989f938c713103ff750 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module MxIsoagent | |
class Client | |
BOARDING_URL = Rails.configuration.mx_iso_agent['boarding_url'] | |
CHECKOUT_URL = Rails.configuration.mx_iso_agent['checkout_url'] | |
INVITE_CODE = Rails.configuration.mx_iso_agent['invite_code'] | |
BOARDING_KEYS = Rails.configuration.mx_iso_agent['api_key'] | |
BUSINESS_TYPES = [ | |
%w[Retail Retail], | |
%w[Internet Internet], | |
%w[Other Other], | |
%w[Healthcare Healthcare], | |
%w[Education Education], | |
%w[Government Government], | |
['Charity/Non-Profit', 'Charity_NonProfit'], | |
%w[B2B B2B] | |
].freeze | |
CORPORATION_TYPES = [ | |
['Sole Proprietor', 'SoleProprietor'], | |
%w[Partnership Partnership], | |
['LLC/LLP', 'LLC_LLP'], | |
['C Corporation', 'CCorp'], | |
['S Corporation', 'SCorp'], | |
%w[Government Government], | |
['501(c) Tax Exempt', 'TaxExempt501'] | |
].freeze | |
def initialize(gateway) | |
@gateway = gateway | |
@payload = Payload.new(gateway) | |
end | |
attr_reader :gateway, :payload | |
def post_invite | |
HTTParty.post("#{BOARDING_URL}/invite", | |
body: MxIsoagent::Payload.new(gateway).to_json, | |
headers: master_headers) | |
end | |
def fetch_merchant | |
HTTParty.get("#{BOARDING_URL}/merchant", | |
query: { referenceId: gateway.reference_token }, | |
headers: master_headers) | |
end | |
def post_keys | |
HTTParty.post("#{CHECKOUT_URL}/application", | |
body: { | |
roleId: 2, | |
merchantId: gateway.merchant_id, | |
name: 'Dime Payments Keys', | |
locked: false | |
}.to_json, | |
headers: merchant_headers) | |
end | |
def fetch_keys | |
HTTParty.get("#{CHECKOUT_URL}/application", | |
query: { merchantId: gateway.merchant_id }, | |
headers: merchant_headers) | |
end | |
private | |
def master_headers | |
{ | |
'Content-Type' => 'application/json', | |
'Authorization' => "Basic #{BOARDING_KEYS}" | |
} | |
end | |
def merchant_headers | |
{ | |
'Content-Type' => 'application/json', | |
'Authorization' => "Basic #{merchant_credentials}" | |
} | |
end | |
def email | |
gateway.merchant_username | |
end | |
def password | |
gateway.merchant_password | |
end | |
def merchant_credentials | |
Base64.strict_encode64("#{email}:#{password}") | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module MxIsoagent | |
class BoardingError < StandardError; end | |
class MerchantAccountCreator | |
def initialize(gateway) | |
@gateway = gateway | |
@error_messages = [] | |
end | |
attr_accessor :gateway, :error_messages | |
def save | |
create_merchant_with_invite_code | |
fetch_and_save_merchant_id | |
create_api_keys | |
fetch_and_save_api_keys | |
result | |
end | |
def create_merchant_with_invite_code | |
# Create the merchant (no echo) | |
# Returns only response code | |
# 201 Created successfully | |
# Any other code is failure | |
with_response_handling { client.post_invite } | |
end | |
# Retrieve the newly created merchant_id based on the reference Id | |
# rubocop:disable Metrics/AbcSize | |
def fetch_and_save_merchant_id | |
merchant_response = (with_response_handling { client.fetch_merchant }) | |
# ubocop:disable Style/GuardClause | |
return unless merchant_response.success? | |
# response will be empty if no keys were found. | |
raise BoardingError, 'Merchant keys could not be found' unless merchant_response.parsed_response.any? | |
gateway.update_attributes( | |
merchant_id: merchant_response.parsed_response.first['id'], | |
status: merchant_response.parsed_response.first['status'] | |
) | |
end | |
# rubocop:enable Metrics/AbcSize | |
# Create the API keys (no echo) | |
def create_api_keys | |
with_response_handling { client.post_keys } | |
end | |
# Retrieve and save the API keys | |
# We do this without response handling because the production API sometimes returns a 403 response if we do this too quickly. | |
def fetch_and_save_api_keys | |
keys_response = client.fetch_keys | |
return unless keys_response.success? | |
gateway.update_attributes( | |
merchant_api_key: keys_response['records'][0]['apiKey'], | |
merchant_api_secret: keys_response['records'][0]['apiSecret'] | |
) | |
end | |
def update_account_status | |
merchant_response = with_response_handling { client.fetch_merchant } | |
gateway.update_attributes(status: merchant_response.parsed_response.first['status']) if merchant_response.success? | |
end | |
private | |
def with_response_handling | |
yield.tap do |response| | |
gateway.responses << response | |
raise BoardingError, response.parsed_response['details']&.join(' ') unless response.success? | |
end | |
end | |
def result | |
OpenStruct.new( | |
success?: true, | |
gateway: gateway | |
) | |
end | |
def payload | |
Payload.new(gateway).to_json | |
end | |
def client | |
@client ||= MxIsoagent::Client.new(gateway) | |
end | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
module MxIsoagent | |
# rubocop:disable Metrics/ClassLength | |
class Payload | |
def initialize(gateway) | |
@gateway = gateway | |
@payments_form_data = ActiveSupport::HashWithIndifferentAccess.new(@gateway.payments_form_data) | |
end | |
attr_reader :gateway, :payments_form_data | |
def to_json | |
to_h.to_json | |
end | |
def to_h | |
%i[base_params hard_coded_params auth_params bank_params | |
terms_and_conditions_params location_params legal_params owner_params].inject({}) do |k, v| | |
k.merge!(send(v)) | |
end | |
end | |
private | |
# include ActionView::Helpers::TextHelper | |
include ActiveSupport::Inflector | |
# Statement Name. string(50) | |
# https://docs.mxisoagent.com/docs/modelInfo/MXA.API.Services.Models.Merchant | |
def statement_name | |
return unless payments_form_data['organization_name'] | |
underscore(parameterize(payments_form_data['organization_name'])).upcase[0, 49] | |
end | |
def email | |
gateway.merchant_username | |
end | |
def password | |
gateway.merchant_password | |
end | |
# rubocop:disable Metrics/AbcSize, Metrics/MethodLength | |
def base_params | |
{ | |
inviteCode: Rails.configuration.mx_iso_agent['invite_code'], | |
referenceId: gateway.reference_token, | |
customerServicePhone: payments_form_data['organization_phone'], | |
statementName: statement_name, | |
statementPhone: payments_form_data['organization_phone'] | |
} | |
end | |
def hard_coded_params | |
{ | |
delivery: '0', | |
hasPhysicalLocation: false, | |
developerPackageOn: true, | |
website: 'https://example.com', | |
returnPolicy: 'Not provided', | |
averageTicket: '100', | |
averageMonthlyVolume: '25000', | |
descriptionOfProducts: 'donations', | |
sponsorBankName: 'Synovus Bank, Columbus, GA', | |
businessType: '8661', | |
legalTaxIdType: 'EIN' | |
} | |
end | |
def auth_params | |
{ | |
mxmUserEmail: email, | |
mxmUserPassword: password | |
} | |
end | |
def bank_params | |
{ | |
depositRoutingNumber: payments_form_data['routing_number'], | |
depositAccountNumber: payments_form_data['account_number'], | |
depositAccountType: payments_form_data['account_type'] | |
} | |
end | |
def terms_and_conditions_params | |
{ | |
agreeTermsAndConditions: payments_form_data['accepts_merchant_services_agreement'], | |
agreeMerchantServices: payments_form_data['accepts_merchant_services_agreement'], | |
agreeInfoAccurate: payments_form_data['accepts_pricing_and_fees'], | |
agreePricingSchedule: payments_form_data['certifies_information_is_correct'] | |
} | |
end | |
def location_params | |
{ | |
locationName: payments_form_data['organization_name'], | |
locationAddress: payments_form_data['organization_street_address'], | |
locationCity: payments_form_data['organization_city'], | |
locationState: payments_form_data['organization_state'], | |
locationZip: payments_form_data['organization_zip'], | |
locationPhone: payments_form_data['organization_phone'] | |
} | |
end | |
def legal_params | |
{ | |
businessCategory: payments_form_data['business_type'], | |
legalAddressIsBusinessAddress: true, | |
legalName: payments_form_data['legal_entity_name'], | |
legalEntity: 1, | |
legalAddress: payments_form_data['legal_entity_street_address'], | |
legalCity: payments_form_data['legal_entity_city'], | |
legalState: payments_form_data['legal_entity_state'], | |
legalZip: payments_form_data['legal_entity_zip'], | |
legalPhone: payments_form_data['organization_phone'], | |
legalCorporationType: payments_form_data['corporate_structure'], | |
legalCorporationDate: payments_form_data['legal_entity_incorporation_date'], | |
legalTaxFilingName: payments_form_data['legal_entity_name'], | |
legalTaxId: payments_form_data['legal_entity_tax_id'], | |
legalEntityState: payments_form_data['legal_entity_state'], | |
businessName: payments_form_data['legal_entity_name'] | |
} | |
end | |
def owner_params | |
{ | |
ownerPercentage: '100', | |
ownerAddressIsBusinessAddress: true, | |
ownerFirstName: payments_form_data['legal_representative_first_name'], | |
ownerLastName: payments_form_data['legal_representative_last_name'], | |
ownerSsn: payments_form_data['legal_representative_ssn'], | |
ownerMobile: payments_form_data['legal_representative_phone'], | |
ownerEmail: payments_form_data['legal_representative_email'], | |
ownerAddress: payments_form_data['legal_representative_street_address'], | |
ownerCity: payments_form_data['legal_representative_city'], | |
ownerState: payments_form_data['legal_representative_state'], | |
ownerZip: payments_form_data['legal_representative_zip'], | |
ownerDob: payments_form_data['legal_representative_dob'] | |
} | |
end | |
# rubocop:enable Metrics/AbcSize, Metrics/MethodLength | |
end | |
# rubocop:enable Metrics/ClassLength | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
class PaymentsForm | |
include ActiveModel::Model | |
include ActiveModel::Validations | |
# Don't rename or remove these attributes. It will result in | |
# ActiveModel::UnknownAttributeError being raised. | |
REQUIRED_ATTRIBUTES = %i[ | |
organization_name | |
organization_street_address | |
organization_city | |
organization_state | |
organization_zip | |
organization_phone | |
organization_email | |
legal_entity_name | |
legal_entity_street_address | |
legal_entity_city | |
legal_entity_state | |
legal_entity_zip | |
legal_entity_incorporation_date | |
legal_entity_tax_id | |
corporate_structure | |
business_type | |
routing_number | |
account_number | |
account_type | |
legal_representative_first_name | |
legal_representative_last_name | |
legal_representative_email | |
legal_representative_ssn | |
legal_representative_dob | |
legal_representative_phone | |
legal_representative_email | |
legal_representative_street_address | |
legal_representative_city | |
legal_representative_state | |
legal_representative_zip | |
].freeze | |
ACCEPTANCE_ATTRIBUTES = %i[ | |
accepts_merchant_services_agreement | |
accepts_pricing_and_fees | |
certifies_information_is_correct | |
].freeze | |
attr_accessor(*REQUIRED_ATTRIBUTES) | |
attr_accessor(*ACCEPTANCE_ATTRIBUTES) | |
def initialize(args) | |
args = args.select { |k, _v| self.class.required_attributes.include?(k.intern) } | |
super(args) | |
end | |
validates(*REQUIRED_ATTRIBUTES, presence: true) | |
validates(*ACCEPTANCE_ATTRIBUTES, acceptance: { message: '' }, allow_nil: false) | |
def self.required_attributes | |
REQUIRED_ATTRIBUTES | ACCEPTANCE_ATTRIBUTES | |
end | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# frozen_string_literal: true | |
class Admin::Settings::PaymentsController < Admin::BaseController | |
before_action :load_gateway | |
def show; end | |
def new | |
@payments_form = PaymentsForm.new(@gateway.payments_form_data) | |
end | |
def create | |
@payments_form = PaymentsForm.new(payments_form_params) | |
# Update the saved merchant data even if it's not valid... | |
@gateway.update_attributes(payments_form_data: @payments_form.as_json) | |
if @payments_form.valid? | |
# Invoke the MerchantAccountCreator | |
begin | |
MxIsoagent::MerchantAccountCreator.new(@gateway).save | |
# rescue MxIsoagent::BoardingError => e | |
# @payments_form.errors.add(:base, e.message) | |
end | |
end | |
respond_with @payments_form, location: admin_settings_payments_path | |
end | |
def update | |
MxIsoagent::MerchantAccountCreator.new(@gateway).fetch_and_save_api_keys | |
redirect_to action: :show | |
end | |
private | |
def load_gateway | |
@organization = Current.organization | |
@gateway = @organization.gateway || @organization.build_gateway | |
end | |
def payments_form_params | |
params.require(:payments_form).permit(*PaymentsForm.required_attributes) | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment