payfrit-works/cfpayment/api/gateway/goemerchant/goemerchant.cfc

380 lines
No EOL
17 KiB
Text
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!---
$Id$
Copyright 2011 Shawn Mckee (http://www.clinicapps.com)
Licensed under the Apache License, Version 2.0 (the "License"); you
may not use this file except in compliance with the License. You may
obtain a copy of the License at:
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
--->
<cfcomponent displayname="GoEMerchant Gateway" extends="cfpayment.api.gateway.base" output="false" hint="Provides credit card process for GoEMerchant">
<!--- gateway specific variables --->
<cfset variables.cfpayment.GATEWAYID = "1" />
<cfset variables.cfpayment.GATEWAY_NAME = "GoEmerchant Gateway" />
<cfset variables.cfpayment.GATEWAY_VERSION = "1" />
<cfset variables.cfpayment.GATEWAY_LIVE_URL = "https://secure.goemerchant.com/secure/gateway/xmlgateway.aspx" />
<cfset variables.cfpayment.GATEWAY_TEST_URL = variables.cfpayment.GATEWAY_LIVE_URL /> <!--- test mode determined by processor, mid, and tid --->
<cfset variables.cfpayment.MerchantAccount = "" />
<cfset variables.cfpayment.Username = "" />
<cfset variables.cfpayment.Password = "" />
<cfset variables.cfpayment.TestMode = true />
<cfset variables.cfpayment.processor = "">
<cfset variables.cfpayment.mid = "" />
<cfset variables.cfpayment.tid = "" />
<cffunction name="init" access="public" output="false" returntype="any">
<cfset super.init(argumentCollection = arguments) />
<cfif variables.cfpayment.TestMode>
<cfset variables.cfpayment.processor = "sandbox">
<cfset variables.cfpayment.mid = arguments.config.mid />
<cfset variables.cfpayment.tid = arguments.config.tid />
</cfif>
<cfreturn this />
</cffunction>
<!--- implemented functions --->
<cffunction name="process" access="private" returntype="struct" output="true">
<cfargument name="payload" type="string" required="true" />
<cfargument name="options" type="struct" required="true" />
<cfset var local = structNew() />
<cfoutput>
<cfsavecontent variable="local.strXML">
<?xml version="1.0" encoding="UTF-8"?>
<TRANSACTION>
  <FIELDS>
    <FIELD KEY="transaction_center_id">#variables.cfpayment.userName#</FIELD>
    <FIELD KEY="gateway_id">#variables.cfpayment.MerchantAccount#</FIELD>
<FIELD KEY="mid">#variables.cfpayment.mid#</FIELD>
<FIELD KEY="tid">#variables.cfpayment.tid#</FIELD>
<FIELD KEY="processor">#variables.cfpayment.processor#</FIELD>
    <FIELD KEY="operation_type">#arguments.options.operationType#</FIELD>
<cfoutput>
#arguments.payload#
</cfoutput>
<cfif !find("::1", cgi.REMOTE_ADDR)>
    <FIELD KEY="remote_ip_address">#cgi.REMOTE_ADDR#</FIELD>
<cfelse>
    <FIELD KEY="remote_ip_address">127.0.0.1</FIELD>
</cfif>
  </FIELDS>
</TRANSACTION>
</cfsavecontent>
</cfoutput>
<cfset local.h = { "Content-Type" = "text/xml" } />
<cfset local.p = local.strXML.trim()>
<cfset local.processorData = createResponse(argumentCollection = super.process(payload = local.p, headers=local.h)) />
<cfif !local.processorData.hasError()>
<cfset local.processorXMLData = XmlParse(local.processorData.getResult())>
<cfset local.fieldNodes = xmlSearch(local.processorXMLData,'/RESPONSE/FIELDS/FIELD')>
<cfloop index="local.field" array="#local.fieldNodes#">
<cfset local.response[field.XmlAttributes.Key] = field.XmlText />
</cfloop>
<cfif structKeyExists(local.response, "status")>
<cfif local.response.status EQ 0>
<cfset local.processorData.setStatus(getService().getStatusUnprocessed()) />
<cfset local.processorData.setAuthorization(local.response.auth_code) />
<cfset local.processorData.setTransactionID(local.response.reference_number) /> <!--- generated by GoEMerchant --->
<cfset local.processorData.setTokenID(local.response.order_id) /> <!--- your order ID sent to GoEMerchant --->
<cfset local.processorData.setMessage(local.response.error) />
<cfelseif local.response.status EQ 1>
<cfset local.processorData.setStatus(getService().getStatusSuccessful()) />
<cfset local.processorData.setAuthorization(local.response.auth_code) />
<cfset local.processorData.setTransactionID(local.response.reference_number) /> <!--- generated by GoEMerchant --->
<cfset local.processorData.setTokenID(local.response.order_id) /> <!--- your order ID sent to GoEMerchant --->
<!--- leave avs response blank if no answer is returned --->
<cfif len(trim(local.response.avs_code))>
<cfset local.processorData.setAVSCode(local.response.avs_code) />
</cfif>
<!--- leave cvv2 response blank if no answer is returned --->
<cfif len(trim(local.response.cvv2_code))>
<cfset local.processorData.setCVVCode(local.response.cvv2_code) />
</cfif>
<cfset local.processorData.setMessage(local.response.auth_response) />
<cfelseif local.response.status EQ 2>
<cfif trim(local.response.auth_code) EQ "">
<cfset local.processorData.setStatus(getService().getStatusDeclined()) />
<cfset local.processorData.setAuthorization(local.response.auth_code) />
<cfset local.processorData.setTransactionID(local.response.reference_number) /> <!--- generated by GoEMerchant --->
<cfset local.processorData.setTokenID(local.response.order_id) /> <!--- your order ID sent to GoEMerchant --->
<cfset local.processorData.setMessage("Declined") />
<cfelse>
<cfset local.processorData.setStatus(getService().getStatusFailure()) />
<cfset local.processorData.setAuthorization(local.response.auth_code) />
<cfset local.processorData.setTransactionID(local.response.reference_number) /> <!--- generated by GoEMerchant --->
<cfset local.processorData.setTokenID(local.response.order_id) /> <!--- your order ID sent to GoEMerchant --->
<cfset local.processorData.setMessage("Auth Code: '#local.response.auth_code#' - Auth Response: '#local.response.auth_response#' - Error: '#local.response.error#'") />
</cfif>
<cfelse>
<cfset local.processorData.setStatus(getService().getStatusUnknown()) />
<cfset local.processorData.setTokenID(arguments.options.order_ID) />
<cfset local.processorData.setMessage("GoEMerchant status unrecognized: #local.response.status# ERROR: #local.response.error#") />
</cfif>
<cfelseif structKeyExists(local.response, "status1")> <!--- void, credit or settle --->
<cfif local.response.status1 EQ 1>
<cfset local.processorData.setStatus(getService().getStatusSuccessful()) />
<cfif structKeyExists(local.response, "batch_number1")>
<cfset local.processorData.setTransactionID(local.response.batch_number1) /> <!--- generated by GoEMerchant for settle --->
</cfif>
<cfset local.processorData.setTokenID(arguments.options.order_ID) /> <!--- your order ID sent to GoEMerchant --->
<cfelseif local.response.status1 EQ 2>
<cfset local.processorData.setStatus(getService().getStatusFailure()) />
<cfset local.processorData.setTransactionID(local.response.reference_number1) /> <!--- generated by GoEMerchant --->
<cfset local.processorData.setTokenID(arguments.options.order_ID) /> <!--- your order ID sent to GoEMerchant --->
<cfset local.processorData.setMessage(local.response.response1) />
<cfelse>
<cfset local.processorData.setStatus(getService().getStatusUnknown()) />
<cfset local.processorData.setTokenID(arguments.options.order_ID) />
<cfset local.processorData.setMessage("Error: '#local.response.error1#' - Response: 'local.response.response1'") />
</cfif>
<cfelse>
<cfset local.processorData.setStatus(getService().getStatusUnknown()) />
<cfset local.processorData.setTransactionID(arguments.options.order_ID) />
<cfset local.processorData.setMessage("GoEMerchant failed to return status") />
</cfif>
<cfelse>
<cfset local.processorData.setStatus(getService().getStatusUnknown()) />
<cfset local.processorData.setTransactionID(arguments.options.order_ID) />
<cfset local.processorData.setMessage("System error") />
</cfif>
<cfreturn local.processorData>
</cffunction>
<cffunction name="purchase" output="false" access="public" returntype="any" hint="Perform an authorization immediately followed by a capture">
<cfargument name="money" type="struct" required="true" />
<cfargument name="account" type="struct" required="true" />
<cfargument name="options" type="struct" required="true" />
<cfset var local = structNew() />
<cfset arguments.options.operationType = "sale" /> <!--- used in process method --->
<cfset local.ccNum = arguments.account.getAccount() />
<cfset local.payload = '<FIELD KEY="order_id">#arguments.options.order_ID#</FIELD>
    <FIELD KEY="total">#numberFormat(arguments.money.getAmount(),'9999.99')#</FIELD>
    <FIELD KEY="card_name">#getCardType(local.ccNum).shortName#</FIELD>
    <FIELD KEY="card_number">#local.ccNum#</FIELD>
    <FIELD KEY="card_exp"> #numberFormat(arguments.account.getMonth(), "00")##right(arguments.account.getYear(), 2)#</FIELD>
    <FIELD KEY="owner_name">#arguments.account.getFirstName()# #arguments.account.getLastName()#</FIELD>
    <FIELD KEY="owner_street"></FIELD>
    <FIELD KEY="owner_city"></FIELD>
    <FIELD KEY="owner_state"></FIELD>
    <FIELD KEY="owner_zip">#arguments.account.getPostalCode()#</FIELD>
    <FIELD KEY="owner_country"></FIELD>
    <FIELD KEY="owner_email"></FIELD>
    <FIELD KEY="owner_phone"></FIELD>' />
<cfif trim(arguments.account.getVerificationValue()) NEQ "">
    <cfset local.payload = local.payload & '<FIELD KEY="cvv2">#arguments.account.getVerificationValue()#</FIELD>' />
</cfif>
<cfset local.response = process(local.payload, options) />
<cfreturn local.response />
</cffunction>
<cffunction name="authorize" output="false" access="public" returntype="any" hint="Verifies payment details with merchant bank">
<cfargument name="money" type="struct" required="true" />
<cfargument name="account" type="struct" required="true" />
<cfargument name="options" type="struct" required="true" />
<cfset var local = structNew() />
<cfset arguments.options.operationType = "auth" /> <!--- used in process method --->
<cfset local.ccNum = arguments.account.getAccount() />
<cfset local.payload = '<FIELD KEY="order_id">#arguments.options.order_ID#</FIELD>
    <FIELD KEY="total">#numberFormat(arguments.money.getAmount(),'9999.99')#</FIELD>
    <FIELD KEY="card_name">#getCardType(local.ccNum).shortName#</FIELD>
    <FIELD KEY="card_number">#local.ccNum#</FIELD>
    <FIELD KEY="card_exp"> #numberFormat(arguments.account.getMonth(), "00")##right(arguments.account.getYear(), 2)#</FIELD>
    <FIELD KEY="owner_name">#arguments.account.getFirstName()# #arguments.account.getLastName()#</FIELD>
    <FIELD KEY="owner_street"></FIELD>
    <FIELD KEY="owner_city"></FIELD>
    <FIELD KEY="owner_state"></FIELD>
    <FIELD KEY="owner_zip">#arguments.account.getPostalCode()#</FIELD>
    <FIELD KEY="owner_country"></FIELD>
    <FIELD KEY="owner_email"></FIELD>
    <FIELD KEY="owner_phone"></FIELD>' />
<cfif trim(arguments.account.getVerificationValue()) NEQ "">
    <cfset local.payload = local.payload & '<FIELD KEY="cvv2">#arguments.account.getVerificationValue()#</FIELD>' />
</cfif>
<cfset local.response = process(local.payload, options) />
<cfreturn local.response />
</cffunction>
<!--- based on the assumption that credits and captures (settles) are done as singletons. The GoEMerchant interface can process mutliple
credits and captures in a single transaction but this code does not support that. --->
<cffunction name="capture" output="false" access="public" returntype="any" hint="Confirms an authorization with direction to charge the account">
<cfargument name="money" type="struct" required="true" />
<cfargument name="authorization" type="numeric" required="true" hint="Transaction ID" />
<cfargument name="options" type="struct" required="true" hint="Must include order_id" />
<cfset var local = structNew() />
<cfset arguments.options.operationType = "settle" /> <!--- used in process method --->
<cfset local.payload = '<FIELD KEY="total_number_transactions">1</FIELD><FIELD KEY="reference_number1">#arguments.authorization#</FIELD><FIELD KEY="settle_amount1">#numberFormat(arguments.money.getAmount(),'9999.99')#</FIELD>'>
<cfset local.response = process(local.payload, arguments.options) />
<cfreturn local.response />
</cffunction>
<cffunction name="credit" output="false" access="public" returntype="any" hint="">
<cfargument name="money" type="struct" required="true" />
<cfargument name="transactionid" type="numeric" required="true" />
<cfargument name="options" type="struct" required="true" hint="Must include order_id" />
<cfset var local = structNew() />
<cfset arguments.options.operationType = "credit" /> <!--- used in process method --->
<cfset local.payload = '<FIELD KEY="total_number_transactions">1</FIELD><FIELD KEY="reference_number1">#arguments.transactionid#</FIELD><FIELD KEY="credit_amount1">#numberFormat(arguments.money.getAmount(),'9999.99')#</FIELD>' />
<cfset local.response = process(local.payload, arguments.options) />
<cfreturn local.response />
</cffunction>
<cffunction name="void" output="false" access="public" returntype="any" hint="">
<cfargument name="transactionid" type="numeric" required="true" />
<cfargument name="options" type="struct" required="true" hint="Must include order_id" />
<cfset var local = structNew() />
<cfset arguments.options.operationType = "void" /> <!--- used in process method --->
<cfset local.payload = '<FIELD KEY="total_number_transactions">1</FIELD><FIELD KEY="reference_number1">#arguments.transactionid#</FIELD>' />
<cfset local.response = process(local.payload, arguments.options) />
<cfreturn local.response />
</cffunction>
<!--- this is a credit card gateway --->
<cffunction name="getIsCCEnabled" output="false" access="public" returntype="boolean" hint="determine whether or not this gateway can accept credit card transactions">
<cfreturn true />
</cffunction>
<!---
// CardTypes Prefix Width
// American Express 34, 37 15
// Diners Club 300 to 305, 36 14
// Carte Blanche 38 14
// Discover 6011 16
// EnRoute 2014, 2149 15
// JCB 3 16
// JCB 2131, 1800 15
// Master Card 51 to 55 16
// Visa 4 13, 16
// http://www.beachnet.com/~hstiles/cardtype.html
// http://www.ros-soft.net/otros/cakephp_blog/creditcard.php.txt
// http://www.rgagnon.com/javadetails/java-0034.html
// Most comprehensive seems to be Wikipedia: http://en.wikipedia.org/wiki/Credit_card_number
--->
<cffunction name="getCardType" access="private" returntype="struct" output="false" hint="Card Type short/long name required by GoEmerchant gateway">
<cfargument name="ccNum" type="numeric" required="true" />
<cfscript>
var local = structNew();
switch(len(arguments.ccNum))
{
case 16:
if(left(arguments.ccNum, 1) == 4)
{
local.returnStruct.shortName = "Visa";
local.returnStruct.longName = "Visa";
}
else if(listFind("51,52,53,54,55", left(arguments.ccNum, 2)))
{
local.returnStruct.shortName = "MasterCard";
local.returnStruct.longName = "Master Card";
}
else if(left(arguments.ccNum, 4) == 6011)
{
local.returnStruct.shortName = "JCB";
local.returnStruct.longName = "JCB";
}
else if(left(arguments.ccNum, 1) == 3)
{
local.returnStruct.shortName = "JCB";
local.returnStruct.longName = "JCB";
}
break;
case 15:
if(listFind("34,37", left(arguments.ccNum, 2)))
{
local.returnStruct.shortName = "Amex";
local.returnStruct.longName = "American Express";
}
else if(listFind("2131,1800", left(arguments.ccNum, 4)))
{
local.returnStruct.shortName = "JCB";
local.returnStruct.longName = "JCB";
}
else if(listFind("2014,2149", left(arguments.ccNum, 4)))
{
local.returnStruct.shortName = "EnRoute";
local.returnStruct.longName = "EnRoute";
}
break;
case 14:
if(left(arguments.ccNum, 2) == 36 OR listFind("301,302,303,304,305", left(arguments.ccNum, 3)))
{
local.returnStruct.shortName = "DinersClub";
local.returnStruct.longName = "Diners Club";
}
else if(left(arguments.ccNum, 2) == 38)
{
local.returnStruct.shortName = "CarteBlanche";
local.returnStruct.longName = "Carte Blanche";
}
break;
case 13:
if(left(arguments.ccNum, 1) == 4)
{
local.returnStruct.shortName = "Visa";
local.returnStruct.longName = "Visa";
}
break;
}
return local.returnStruct;
</cfscript>
</cffunction>
</cfcomponent>