dependencies
| (this space intentionally left almost blank) | |||||||||
ARB - Automatic Recurring BillingThis namespace implements the functions require to list, get, create, and update recurring billing subscriptions. | (ns authnet-clj.arb (:require [authnet-clj.core :refer :all] )) | |||||||||
Records to facilitate subscription update.The following example illustrates the basic structure for a subscription payment update. The records defined below reflect each of the segments of this structure.
| ||||||||||
The billing address associated with a credit card update | (defrecord billTo [firstName lastName address city state zip]) | |||||||||
Credit card record with card number and expiration date attributes | (defrecord creditCard [cardNumber expirationDate]) | |||||||||
A payment segnment includes a credit card map | (defrecord payment [^creditCard creditCard]) | |||||||||
A subscription update can include a new CC as well as
a new billTo (name, address). The | (defrecord subscription [^payment payment ^billTo billTo]) | |||||||||
Makes the map required to submit a subscription payment method update request. | (defn make-subscription-payment-update ([credit-card expiration-date] (->subscription (->payment (->creditCard credit-card expiration-date)))) ([credit-card expiration-date f-name l-name address city state zip] (->subscription (->payment (->creditCard credit-card expiration-date)) (->billTo f-name l-name address city state zip)))) | |||||||||
Concrete Subscription Request Functions | ||||||||||
Retrieves the subscription status for the specified subscription. | (defn get-subscription-status [subscription-id] (let [creds (get-credentials) url (get-endpoint creds)] (do-request url (build-request :ARBGetSubscriptionStatusRequest {:subscriptionId subscription-id} ) ))) | |||||||||
Retrieves the details of the specified subscription. | (defn get-subscription [subscription-id] (let [creds (get-credentials) url (get-endpoint creds)] (do-request url (build-request :ARBGetSubscriptionRequest {:subscriptionId subscription-id} ) ))) | |||||||||
Retrieves a sequence of subscriptions in the specified status. Inputs: search-type: cardExpiringThisMonth subscriptionActive subscriptionInactive subscriptionExpiringThisMonth | (defn get-subscriptions [search-type] (let [creds (get-credentials) url (get-endpoint creds)] (do-request url (build-request :ARBGetSubscriptionListRequest {:searchType search-type })))) | |||||||||
Updates the Credit Card number and Expirate Date of the specified subscription. It can also update the Credit Card holder's name and address if 9-arity function is invoked. | (defn update-subscription ([subscription-id cc-number cc-expiration] (let [creds (get-credentials) url (get-endpoint creds) ] (do-request url (build-request :ARBUpdateSubscriptionRequest {:subscriptionId subscription-id :subscription (make-subscription-payment-update cc-number cc-expiration )})))) ([subscription-id cc-number cc-expiration fname lname address city state zip] (let [creds (get-credentials) url (get-endpoint creds) ] (do-request url (build-request :ARBUpdateSubscriptionRequest {:subscriptionId subscription-id :subscription (make-subscription-payment-update cc-number cc-expiration fname lname address city state zip)}))))) | |||||||||
Makes a request to cancel the identified subscription. | (defn cancel-subscription [subscription-id] (let [creds (get-credentials) url (get-endpoint creds) ] (do-request url (build-request :ARBCancelSubscriptionRequest {:subscriptionId subscription-id})))) | |||||||||
Customer ProfileThis namespace implements the functions related to retrieving and updating customer profiles. | (ns authnet-clj.profiles (:require [authnet-clj.core :refer :all])) | |||||||||
Retrieves a customer profile. | (defn get-customer-profile [customer-profile-id] (let [creds (get-credentials) url (get-endpoint creds) ] (do-request url (build-request :getCustomerProfileRequest {:customerProfileId customer-profile-id :includeIssuerInfo "true"})))) | |||||||||
Lists all payment profiles that expire in the specified month. month: "2020-12" | (defn list-expiring-customers-payment-profiles [month] (let [creds (get-credentials) url (get-endpoint creds) ] (do-request url (build-request :getCustomerPaymentProfileListRequest {:searchType "cardsExpiringInMonth" :month month})))) | |||||||||
Lists all customers profiles IDs. | (defn list-customers-profile-ids [] (let [creds (get-credentials) url (get-endpoint creds) ] (do-request url (build-request :getCustomerProfileIdsRequest {} )))) | |||||||||
Core Common functionsThis namespace holds core functions used by each of the (ARB, CIM, Trans) request-specific namespaces. | (ns authnet-clj.core (:require [cheshire.core :refer :all ] [clj-http.client :as client]) (:gen-class)) | |||||||||
Defines the sandbox and production end-points | (def endpoints { :sandbox "https://apitest.authorize.net/xml/v1/request.api" :production "https://api.authorize.net/xml/v1/request.api" }) | |||||||||
Retrieves the Authorize.net credentials from environment variables. | (defn get-credentials [] (let [name (System/getenv "AUTHORIZENET_LOGIN_ID") key (System/getenv "AUTHORIZENET_TRANSACTION_KEY") gateway (System/getenv "AUTHORIZENET_GATEWAY") ] (if (nil? name) (throw (ex-info "Environment variable AUTHORIZENET_LOGIN_ID is missing" {}))) (if (nil? key) (throw (ex-info "Environment variable AUTHORIZENET_TRANSACTION_KEY is missing" {}))) (if (nil? gateway) (throw (ex-info "Environment variable AUTHORIZENET_GATEWAY is missing" {}))) {:name name :transactionKey key :gateway gateway } )) | |||||||||
Helper functions to get each Authorize.net credential variable. | (defn get-name [creds] (:name (get-credentials))) (defn get-transaction-key [creds] (:transactionKey (get-credentials))) (defn get-gateway [creds] (keyword (:gateway (get-credentials)) ) ) (defn get-endpoint [creds] ((get-gateway creds) endpoints)) | |||||||||
Common transaction request maps generators. These are used within each of the API segements (ARB, Customer Profile, etc.) | (defn get-marchant-authentication-map [creds] {:merchantAuthentication {:name (:name creds) :transactionKey (:transactionKey creds)}}) | |||||||||
Generates the complete transaction request map including the transaction name along with the merchant Authentication segment followed by the transaction payload. Inputs: transaction-name: a keyword, such as :ARBGetSubscriptionstatusrequest that identifies the transactions to be submitted. merchantauth-map: a map with a single key :merchantAuthentication and which value is a map containing the API Login ID and API Transaction Key. Note: Use the get-merchant-authentication-map helper to generate the merchantauth-map. payload-map: a map of k/v that is specific to the transaction (transaction-name). (https://developer.authorize.net/api/reference) Output: A map similar to the one depicted below, but with the k/v that are specific to a transaction after the merchantAuthentication map.
| (defn get-transaction-map [merchantauth-map transaction-name payload-map] {transaction-name (merge merchantauth-map payload-map) }) | |||||||||
Request builder responsible for creating a properly formed request map including the merchant Authentication segment. | (defn build-request [request-type request-payload] (-> (get-credentials) (get-marchant-authentication-map) (get-transaction-map request-type request-payload ))) | |||||||||
Request producer responsible for issuing the POST request to the Authorize.Net end-point specified via the environment variables. Note: Authorize.Net returns BOM (Byte Order Marker) byte that screws up the JSON parser. The combination of reading the body as a stream and removing the BOM does the trick. | (defn do-request "Request producer responsible for issuing the POST request to the Authorize.Net end-point specified via the environment variables. Note: Authorize.Net returns BOM (Byte Order Marker) byte that screws up the JSON parser. The combination of reading the body as a stream and removing the BOM \uFEFF does the trick. " [url query] (let [res (client/post url {:body (generate-string query ) :accept :json :body-encoding "UTF-16" :as :stream :throw-exceptions? false :content-type :json}) ] (-> res (:body) (slurp) (clojure.string/replace #"\r\n|\n|\r|\uFEFF" "") (parse-string true)))) | |||||||||