module ActiveMerchant #:nodoc: module Billing #:nodoc: class ModernPaymentsCimGateway < Gateway #:nodoc: self.test_url = 'https://secure.modpay.com/netservices/test/ModpayTest.asmx' self.live_url = 'https://secure.modpay.com/ws/modpay.asmx' LIVE_XMLNS = 'https://secure.modpay.com/ws/' TEST_XMLNS = 'https://secure.modpay.com/netservices/test/' self.supported_countries = ['US'] self.supported_cardtypes = %i[visa master american_express discover] self.homepage_url = 'http://www.modpay.com' self.display_name = 'Modern Payments' SUCCESS_MESSAGE = 'Transaction accepted' FAILURE_MESSAGE = 'Transaction failed' ERROR_MESSAGE = 'Transaction error' PAYMENT_METHOD = { check: 1, credit_card: 2 } def initialize(options = {}) requires!(options, :login, :password) super end def create_customer(options = {}) post = {} add_customer_data(post, options) add_address(post, options) commit('CreateCustomer', post) end def modify_customer_credit_card(customer_id, credit_card) raise ArgumentError, 'The customer_id cannot be blank' if customer_id.blank? post = {} add_customer_id(post, customer_id) add_credit_card(post, credit_card) commit('ModifyCustomerCreditCard', post) end def authorize_credit_card_payment(customer_id, amount) raise ArgumentError, 'The customer_id cannot be blank' if customer_id.blank? post = {} add_customer_id(post, customer_id) add_amount(post, amount) commit('AuthorizeCreditCardPayment', post) end def create_payment(customer_id, amount, options = {}) raise ArgumentError, 'The customer_id cannot be blank' if customer_id.blank? post = {} add_customer_id(post, customer_id) add_amount(post, amount) add_payment_details(post, options) commit('CreatePayment', post) end private def add_payment_details(post, options) post[:pmtDate] = (options[:payment_date] || Time.now.utc).strftime('%Y-%m-%dT%H:%M:%SZ') post[:pmtType] = PAYMENT_METHOD[options[:payment_method] || :credit_card] end def add_amount(post, money) post[:pmtAmount] = amount(money) end def add_customer_id(post, customer_id) post[:custId] = customer_id end def add_customer_data(post, options) post[:acctNum] = options[:customer] end def add_address(post, options) address = options[:billing_address] || options[:address] || {} if name = address[:name] post[:firstName], post[:lastName] = split_names(name) else post[:firstName] = address[:first_name] post[:lastName] = address[:last_name] end post[:address] = address[:address1] post[:city] = address[:city] post[:state] = address[:state] post[:zip] = address[:zip] post[:phone] = address[:phone] post[:fax] = address[:fax] post[:email] = options[:email] end def add_credit_card(post, credit_card) post[:ccName] = credit_card.name post[:ccNum] = credit_card.number post[:expMonth] = credit_card.month post[:expYear] = credit_card.year end def build_request(action, params) xml = Builder::XmlMarkup.new indent: 2 xml.instruct! xml.tag! 'env:Envelope', { 'xmlns:xsd' => 'http://www.w3.org/2001/XMLSchema', 'xmlns:env' => 'http://schemas.xmlsoap.org/soap/envelope/', 'xmlns:xsi' => 'http://www.w3.org/2001/XMLSchema-instance' } do xml.tag! 'env:Body' do xml.tag! action, { 'xmlns' => xmlns(action) } do xml.tag! 'clientId', @options[:login] xml.tag! 'clientCode', @options[:password] params.each { |key, value| xml.tag! key, value } end end end xml.target! end def xmlns(action) if test? && action == 'AuthorizeCreditCardPayment' TEST_XMLNS else LIVE_XMLNS end end def url(action) if test? && action == 'AuthorizeCreditCardPayment' self.test_url else self.live_url end end def commit(action, params) data = ssl_post(url(action), build_request(action, params), { 'Content-Type' => 'text/xml; charset=utf-8', 'SOAPAction' => "#{xmlns(action)}#{action}" } ) response = parse(action, data) Response.new(successful?(action, response), message_from(action, response), response, test: test?, authorization: authorization_from(action, response), avs_result: { code: response[:avs_code] } ) end def authorization_from(action, response) response[authorization_key(action)] end def authorization_key(action) action == 'AuthorizeCreditCardPayment' ? :trans_id : "#{action.underscore}_result".to_sym end def successful?(action, response) key = authorization_key(action) if key == :trans_id response[:approved] == 'true' else response[key].to_i > 0 end end def message_from(action, response) if response[:faultcode] ERROR_MESSAGE elsif successful?(action, response) SUCCESS_MESSAGE else FAILURE_MESSAGE end end def parse(action, xml) response = {} response[:action] = action xml = REXML::Document.new(xml) if root = REXML::XPath.first(xml, "//#{action}Response") root.elements.to_a.each do |node| parse_element(response, node) end elsif root = REXML::XPath.first(xml, '//soap:Fault') root.elements.to_a.each do |node| response[node.name.underscore.to_sym] = node.text end end response end def parse_element(response, node) if node.has_elements? node.elements.each { |e| parse_element(response, e) } else response[node.name.underscore.to_sym] = node.text.to_s.strip end end end end end