Files
danbooru/app/logical/authorize_net_client.rb
evazion 1eb15da7c5 upgrades: add authorize.net integration.
Add integration for accepting payments with Authorize.net.

https://developer.authorize.net/hello_world.html
2022-05-15 01:47:45 -05:00

149 lines
4.8 KiB
Ruby

# frozen_string_literal: true
# An API client for Authorize.net. Used for processing payments for user upgrades.
#
# https://developer.authorize.net/api.html
# https://developer.authorize.net/api/reference/index.html
class AuthorizeNetClient
class Error < StandardError; end
attr_reader :login_id, :transaction_key, :test_mode, :http
def initialize(login_id: Danbooru.config.authorize_net_login_id, transaction_key: Danbooru.config.authorize_net_transaction_key, test_mode: Danbooru.config.authorize_net_test_mode, http: Danbooru::Http.new)
@login_id = login_id
@transaction_key = transaction_key
@test_mode = test_mode
@http = http
end
concerning :ApiMethods do
def authenticate_test
post!(
authenticateTestRequest: {
merchantAuthentication: {
name: login_id,
transactionKey: transaction_key,
}
}
)
end
# https://developer.authorize.net/api/reference/index.html#transaction-reporting-get-transaction-details
def get_transaction(transaction_id)
post!(
getTransactionDetailsRequest: {
merchantAuthentication: {
name: login_id,
transactionKey: transaction_key,
},
transId: transaction_id,
}
)
end
# https://developer.authorize.net/api/reference/index.html#accept-suite-get-an-accept-payment-page
def get_hosted_payment_page(reference_id:, settings: {}, **transaction_request)
post!(
getHostedPaymentPageRequest: {
merchantAuthentication: {
name: login_id,
transactionKey: transaction_key,
},
refId: reference_id,
transactionRequest: transaction_request,
"hostedPaymentSettings": {
"setting": hosted_payment_settings(settings),
},
}
)
end
def hosted_payment_settings(settings)
settings.map do |name, hash|
{
"settingName": "hostedPayment#{name.to_s.camelize}Options",
"settingValue": hash.to_json,
}
end
end
def post!(**request)
resp = http.post!(api_url, json: request)
body = resp.body.to_s.delete_prefix("\xEF\xBB\xBF") # delete UTF-8 BOM
json = JSON.parse(body).with_indifferent_access
if json.dig(:messages, :resultCode) != "Ok"
code = json.dig(:messages, :message, 0, :code)
text = json.dig(:messages, :message, 0, :text)
raise Error, "Authorize.net call failed (request=#{request.keys.first} code=#{code} text=#{text})"
else
json
end
end
# https://developer.authorize.net/api/reference/index.html#gettingstarted-section-section-header
def api_url
if test_mode
"https://apitest.authorize.net/xml/v1/request.api"
else
"https://api.authorize.net/xml/v1/request.api"
end
end
# https://developer.authorize.net/api/reference/features/accept_hosted.html#Form_POST_URLs
def payment_page_url
if test_mode
"https://test.authorize.net/payment/payment"
else
"https://accept.authorize.net/payment/payment"
end
end
end
# https://developer.authorize.net/api/reference/features/webhooks.html
concerning :WebhookApiMethods do
# https://developer.authorize.net/api/reference/features/webhooks.html#List_My_Webhooks
def webhooks
webhook_get!("webhooks")
end
# https://developer.authorize.net/api/reference/features/webhooks.html#Get_a_Webhook
def webhook(webhook_id)
webhook_get!("webhooks/#{webhook_id}")
end
# https://developer.authorize.net/api/reference/features/webhooks.html#Retrieve_Notification_History
def notifications(status: nil)
webhook_get!("notifications", params: { deliveryStatus: status }.compact)
end
# https://developer.authorize.net/api/reference/features/webhooks.html#Retrieve_a_Specific_Notification's_History
def notification(notification_id)
webhook_get!("notifications/#{notification_id}")
end
# https://developer.authorize.net/api/reference/features/webhooks.html#Create_A_Webhook
def create_webhook(name:, url:, eventTypes:, status: "active")
webhook_post!("webhooks", form: { name: name, url: url, eventTypes: eventTypes, status: status })
end
def webhook_get!(path, **options)
http.basic_auth(user: login_id, pass: transaction_key).get!(webhook_url(path), **options).parse
end
def webhook_post!(path, **options)
http.basic_auth(user: login_id, pass: transaction_key).post!(webhook_url(path), **options).parse
end
# https://developer.authorize.net/api/reference/features/webhooks.html#API_Endpoint_Hosts
def webhook_url(path)
if test_mode
"https://apitest.authorize.net/rest/v1/#{path}"
else
"https://api.authorize.net/rest/v1/#{path}"
end
end
end
end